Create flavors and networks

Sem-Ver: feature

Change-Id: I728667e557c3d37296a13c9e3356d419e683a02d
diff --git a/molecule/default/heat/stack.yaml b/molecule/default/heat/stack.yaml
index 113ddb8..5bd59dd 100644
--- a/molecule/default/heat/stack.yaml
+++ b/molecule/default/heat/stack.yaml
@@ -102,6 +102,9 @@
       cidr: { get_param: external_cidr }
       dns_nameservers: { get_param: nameservers }
       gateway_ip: null
+      allocation_pools:
+        - start: 10.96.250.100
+          end: 10.96.250.150
 
   external_network_vip:
     type: OS::Neutron::Port
diff --git a/playbooks/generate_workspace.yml b/playbooks/generate_workspace.yml
index 7556f41..b3b7cf1 100644
--- a/playbooks/generate_workspace.yml
+++ b/playbooks/generate_workspace.yml
@@ -257,19 +257,86 @@
       # NOTE(mnaser): We don't want to override existing Ceph configurations,
       #               so we generate a stub one if and only if it doesn't exist
       when: item.key not in neutron
-      # NOTE(mnaser): This is absolutely hideous but there's no clean way of
-      #               doing this using `with_fileglob` or `with_filetree`
       with_dict:
         openstack_helm_neutron_values:
           conf:
             auto_bridge_add:
               br-ex: ens4
+        openstack_helm_neutron_networks:
+          - name: public
+            external: true
+            shared: true
+            mtu_size: 1500
+            port_security_enabled: true
+            provider_network_type: flat
+            provider_physical_network: external
+            subnets:
+              - name: public-subnet
+                cidr: 10.96.250.0/24
+                gateway_ip: 10.96.250.1
+                allocation_pool_start: 10.96.250.200
+                allocation_pool_end: 10.96.250.220
+                dns_nameservers:
+                  - 1.1.1.1
+                  - 1.0.0.1
+                enable_dhcp: true
 
     - name: Write new Neutron configuration file to disk
       ansible.builtin.copy:
         content: "{{ neutron | to_nice_yaml(indent=2, width=180) }}"
         dest: "{{ _neutron_path }}"
 
+- name: Generate Nova configuration for workspace
+  hosts: localhost
+  gather_facts: false
+  vars:
+    _nova_path: "{{ workspace_path }}/group_vars/all/nova.yml"
+    # Input variables
+  tasks:
+    - name: Ensure the Nova configuration file exists
+      ansible.builtin.file:
+        path: "{{ _nova_path }}"
+        state: touch
+
+    - name: Load the current Nova configuration into a variable
+      ansible.builtin.include_vars:
+        file: "{{ _nova_path }}"
+        name: nova
+
+    - name: Generate Nova values for missing variables
+      ansible.builtin.set_fact:
+        nova: "{{ nova | default({}) | combine({item.key: item.value}) }}"
+      # NOTE(mnaser): We don't want to override existing Nova configurations,
+      #               so we generate a stub one if and only if it doesn't exist
+      when: item.key not in nova
+      with_dict:
+        openstack_helm_nova_flavors:
+          - name: m1.tiny
+            ram: 512
+            disk: 1
+            vcpus: 1
+          - name: m1.small
+            ram: 2048
+            disk: 20
+            vcpus: 1
+          - name: "m1.medium"
+            ram: 4096
+            disk: 40
+            vcpus: 2
+          - name: "m1.large"
+            ram: 8192
+            disk: 80
+            vcpus: 4
+          - name: "m1.xlarge"
+            ram: 16384
+            disk: 160
+            vcpus: 8
+
+    - name: Write new Nova configuration file to disk
+      ansible.builtin.copy:
+        content: "{{ nova | to_nice_yaml(indent=2, width=180) }}"
+        dest: "{{ _nova_path }}"
+
 - name: Generate secrets for workspace
   hosts: localhost
   gather_facts: false
@@ -349,4 +416,4 @@
       ansible.builtin.shell:
         ansible-vault encrypt --vault-password-file {{ secrets_vault_password_file }} {{ secrets_path }}
       when:
-        - secrets_vault_password_file is defined
\ No newline at end of file
+        - secrets_vault_password_file is defined
diff --git a/releasenotes/notes/create-cloud-resources-dd6b1441b047fe98.yaml b/releasenotes/notes/create-cloud-resources-dd6b1441b047fe98.yaml
new file mode 100644
index 0000000..e0bc21f
--- /dev/null
+++ b/releasenotes/notes/create-cloud-resources-dd6b1441b047fe98.yaml
@@ -0,0 +1,3 @@
+---
+features:
+  - Create cloud resources such as networks and flavors
\ No newline at end of file
diff --git a/roles/openstack_helm_neutron/tasks/main.yml b/roles/openstack_helm_neutron/tasks/main.yml
index b11a224..190decc 100644
--- a/roles/openstack_helm_neutron/tasks/main.yml
+++ b/roles/openstack_helm_neutron/tasks/main.yml
@@ -37,6 +37,23 @@
     openstack_helm_ingress_service_name: neutron-server
     openstack_helm_ingress_service_port: 9696
 
+- name: Wait until network service ready
+  kubernetes.core.k8s_info:
+    api_version: apps/v1
+    kind: Deployment
+    name: neutron-server
+    namespace: openstack
+    wait_sleep: 10
+    wait_timeout: 600
+    wait: true
+    wait_condition:
+      type: Available
+      status: true
+
+- name: Install openstacksdk
+  ansible.builtin.pip:
+    name: openstacksdk
+
 - name: Create networks
   openstack.cloud.network:
     auth:
diff --git a/roles/openstack_helm_nova/tasks/main.yml b/roles/openstack_helm_nova/tasks/main.yml
index b48b1db..a719f44 100644
--- a/roles/openstack_helm_nova/tasks/main.yml
+++ b/roles/openstack_helm_nova/tasks/main.yml
@@ -110,6 +110,23 @@
     openstack_helm_ingress_service_name: nova-novncproxy
     openstack_helm_ingress_service_port: 6080
 
+- name: Wait until compute api service ready
+  kubernetes.core.k8s_info:
+    api_version: apps/v1
+    kind: Deployment
+    name: nova-api-osapi
+    namespace: openstack
+    wait_sleep: 10
+    wait_timeout: 600
+    wait: true
+    wait_condition:
+      type: Available
+      status: true
+
+- name: Install openstacksdk
+  ansible.builtin.pip:
+    name: openstacksdk
+
 - name: Create flavors
   openstack.cloud.compute_flavor:
     auth: