OpenStack resources role

The OpenStack resources role is used to declaratively create and manage OpenStack cloud resources. You define the resources you want in variables, and the role ensures they are consistently provisioned and kept in the desired state. This role can provision and manage the following types of OpenStack resources:

  • Identity resources: domains, projects, users, roles, endpoints, and quotas

  • Compute resources: host aggregates, flavors, flavor access rules, and keypairs

  • Networking resources: networks and subnets

  • Image resources: image upload, registration, and rotation

It applies these definitions as code, so environments can be bootstrapped and maintained in a repeatable and controlled way.

Default variables

openstack_resources_cloud_name: default
openstack_resources_interface: internal
openstack_resources_region_name: "{{ service_region | default('RegionOne') }}"
openstack_resources_setup_host: "{{ openstack_service_setup_host | default('localhost') }}"
openstack_resources_python_interpreter: >-
  {{
    openstack_service_setup_host_python_interpreter | default((openstack_resources_setup_host == 'localhost') | ternary(
      ansible_playbook_python, ansible_facts['python']['executable']))
  }}

openstack_resources_deploy_host: localhost
openstack_resources_deploy_python_interpreter: "{{ ansible_playbook_python }}"

# Define this variable to provide mappings that needs to be created
# It will be iterated over and supplied to openstack.osa.service_setup role
# Example:
# openstack_resources_identity:
#   domains:
#     - name: MyDomain
#       description: Custom domain
#   projects:
#     - name: someproject
#       description: My project
#       domain: Default
#   users:
#     - name: "tempest"
#       password: "{{ tempest_service_password }}"
#       project: service
#       role:
#         - "member"
#   catalog:
#     - name: "myservice"
#       type: "billing"
#       description: "our internal service"
#   endpoints:
#     - interface: "public"
#       url: "{{ myservice_service_publicurl }}"
#       service: "myservice"
#   quotas:
#     - name: some_project
#       cores: 100
#       gigabytes: 1000
#       instances: 50
#       networks: 10
#       volumes: 20
openstack_resources_identity: {}

# Define this variable to provide mappings to manage compute resources
# openstack_resources_compute:
#   aggregates:
#     - name: az1
#       availability_zone: "az1"
#       hosts: "{{ groups['nova_compute'] | map('extract', hostvars, ['ansible_facts', 'hostname']) }}"
#       exclusive: false
#     - name: otheraggregate
#       hosts: "{{ groups['nova_compute'] | map('extract', hostvars, ['ansible_facts', 'hostname']) }}"
#   flavors:
#     - specs:
#         - name: b.1c0.5gb
#           vcpus: 1
#           ram: 500
#         - name: b.1c1gb
#           vcpus: 1
#           ram: 1024
#           state: present
#         - name: b.1c2gb
#           vcpus: 1
#           ram: 2048
#           public: false
#       extra_specs:
#         quota:disk_total_iops_sec: '5000'
#       access:
#         - project: tenant1
#           project_domain: Default
#           state: present
#   keypairs:
#     - name: octavia_key
#       path: /root/.ssh/octavia_rsa # path on the localhost, where keypair will be placed
#       key_format: ssh
#       size: 4096
#       state: present
#       type: rsa
openstack_resources_compute: {}

# Define this variable to provide mappings to manage network resources
# openstack_resources_network:
#   address_scopes:
#     - name: external
#       ip_version: 6
#       shared: true
#   subnet_pools:
#     - name: main
#       address_scope: external
#       prefixes:
#         - 192.168.0.0/16
#       default_prefix: 25
#       max_prefix: 29
#       min_prefix: 23
#       quota: 22
#       default: true
#       shared: true
#   networks:
#     - name: tenant_network
#       state: present
#       external: true
#       shared: false
#       network_type: vlan
#       segmentation_id: 200
#       subnets:
#         - name: vlan-subnet
#           cidr: 192.168.20.0/24
#           gateway: 192.168.20.254
#         - name: vlan-subnet-no-gateway
#           cidr: 192.168.21.0/24
#           gateway: null
#   routers:
#     - name: my_router
#       network: public
#       interfaces:
#       - vlan-subnet
#   security_groups:
#     - name: my_group
#       state: present
#       description: My security group
#       security_group_rules:
#         - direction: ingress
#           port_range_min: 80
#           port_range_max: 80
#           protocol: tcp
#           remote_ip_prefix: 192.168.0.0/16
openstack_resources_network: {}

# Define this variable to manage OpenStack images
# openstack_resources_image:
#   image_force_upload: false
#   image_upload_batch: 3
#   image_async_timeout: 600
#   image_async_retries: 200
#   images:
#     - name: cirros
#       # Either `url` or `filename` is required.
#       url: https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img
#       # filename:
#       # checksum: # md5 only is supported. Required for image rotation.
#       # checksum_compressed: # md5 only is supported. Used for compressed images download process
#       # compressed_format: # xz or gz are supported
#       disk_format: qcow2
#       visibility: private
#       owner: service
#       owner_domain: default
#       # Attempt to delete "rotated", except last kept copies.
#       keep_copies: 3
#       # Supported hide methods: private, shared, community. Required if needed to hide old images.
#       hide_method: community
#       tags:
#         - managed_by_OSA
#       properties:
#         architecture: x86_64
#         hypervisor_type: qemu
#         os_distro: Cirros
openstack_resources_image: {}

# Define this variable to manage OpenStack COE cluster templates and clusters
# openstack_resources_coe:
#   clusters:
#     - template_uuid:
#       discovery_url:
#       flavor_id:
#       floating_ip_enabled:
#       keypair:
#       labels:
#       master_count:
#       node_count:
#   templates:
#     - state: present
#       coe: kubernetes
#       dns_nameserver: "8.8.8.8"
#       docker_storage_driver: "devicemapper"
#       docker_volume_size: "10"
#       external_network_id: "public"
#       fixed_network: "private"
#       fixed_subnet: "subnet"
#       flavor_id: "s1.big"
#       floating_ip_enabled: True
#       http_proxy: "{{ http_proxy }}"
#       https_proxy: "{{ https_proxy }}"
#       image_id: "cirros"
#       keypair: "key"
#       labels:
#         kube_tag: v1.25.9
#         cinder_csi_enabled: true
#       master_flavor_id: "s1.normal"
#       master_lb_enabled: "True"
#       name: "Template"
#       network_driver: "calico"
#       no_proxy: "{{ no_proxy }}"
#       public: "True"
#       registry_enabled: "True"
#       server_type: "vm"
#       tls_disabled: "False"
#       volume_driver: "cinder"
#       clusters:
#         - discovery_url:
#           flavor_id:
#           floating_ip_enabled:
#           keypair:
#           labels:
#           master_count:
#           node_count:
openstack_resources_coe: {}

The openstack_resources_* variables shown above are the role’s own variable names. This role is reused by other roles that provision their own resources internally, so when defining resources in user_variables.yml for use with the openstack.osa.openstack_resources playbook, use the corresponding openstack_user_* variable instead:

Set in user_variables.yml

Consumed by the role as

openstack_user_identity

openstack_resources_identity

openstack_user_compute

openstack_resources_compute

openstack_user_network

openstack_resources_network

openstack_user_image

openstack_resources_image

openstack_user_coe

openstack_resources_coe

Example of using

Images, flavors, and other resources can be defined in user_variables.yml using the openstack_user_* variables listed above, and deployed with the openstack.osa.openstack_resources playbook. The role will ensure the resources exist in OpenStack and are kept in the desired state.

The example below uploads the AlmaLinux 10 GenericCloud image and creates two compute flavors.

# === OpenStack Images ===
openstack_user_image:
  images:
    - name: almalinux-10
      url: https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2
      disk_format: qcow2
      container_format: bare
      visibility: public
      min_disk: 10
      min_ram: 1024
      state: present

# === OpenStack Flavors ===
openstack_user_compute:
  flavors:
    - specs:
        - name: m1.small
          vcpus: 1
          ram: 2048        # MB
          disk: 20         # GB
          public: true
          state: present

        - name: m1.medium
          vcpus: 2
          ram: 4096
          disk: 40
          public: true
          state: present

Network resources follow the same pattern, via openstack_user_network:

# === OpenStack Networks ===
openstack_user_network:
  networks:
    - name: project_network
      state: present
      external: true
      shared: false
      network_type: vlan
      physical_network: physnet1
      segmentation_id: 200
      subnets:
        - name: project-subnet
          cidr: 192.168.20.0/24
          gateway: 192.168.20.254

After saving the variables file, apply the configuration with:

# openstack-ansible openstack.osa.openstack_resources

The role will:

  • download and upload the AlmaLinux 10 image

  • create (or update) the m1.small and m1.medium flavors

  • create (or update) the project_network and its subnet

You can also apply only a specific type of resources by running the playbook with the appropriate tag. For example:

Compute resources (flavors, keypairs)
# openstack-ansible openstack.osa.openstack_resources --tags compute-resources

Image resources (image upload/registration/rotation)
# openstack-ansible openstack.osa.openstack_resources --tags image-resources

Network resources (networks, subnets)
# openstack-ansible openstack.osa.openstack_resources --tags network-resources