diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000..1cf307a --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,33 @@ +--- +name: Pull request +"on": + pull_request: +jobs: + lint: + runs-on: ubuntu-22.04 + permissions: {} + strategy: + fail-fast: false + matrix: + include: + # NOTE(upgrade): Keep these in sync with Kayobe's supported Ansible and Python versions (see release notes). + - ansible: "2.16" + python: "3.12" + name: Ansible ${{ matrix.ansible }} lint with Python ${{ matrix.python }} + steps: + - name: GitHub Checkout ๐Ÿ›Ž + uses: actions/checkout@v4 + + - name: Setup Python ${{ matrix.python-version }} ๐Ÿ + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + + - name: Install dependencies ๐Ÿ“ฆ + run: | + python -m pip install --upgrade pip + pip install ansible-core==${{ matrix.ansible }}.* ansible-lint + + - name: Linting code ๐Ÿงช + run: | + ansible-lint -v --force-color diff --git a/README.rst b/README.rst index 13f69ba..a520786 100644 --- a/README.rst +++ b/README.rst @@ -3,26 +3,26 @@ OpenStack Configuration ============================================= This project contains Ansible playbooks and configuration of infrastructure on -an existing OpenStack cloud for the OpenStack system. (Supported up to Yoga -release.) +an existing OpenStack cloud for the OpenStack system. Preparation =========== Ensure that Ansible is installed, either via the system package manager or pip. -If required, use a virtualenv to avoid interference with the system python -packages. For example: +It is recommended that you use a python virtual environment to avoid +interference with the system python packages. For example: .. code-block:: - $ virtualenv venv - $ source venv/bin/activate + $ python3 -m venv openstack-venv + $ source openstack-venv/bin/activate $ python -m pip install --upgrade pip $ pip install -r requirements.txt Install Ansible role and collection dependencies from Ansible Galaxy: .. code-block:: + $ ansible-galaxy collection install \ -p ansible/collections \ -r requirements.yml @@ -87,10 +87,16 @@ variables in `etc/openstack-config.yml` .. code-block:: yaml - magnum_default_master_flavor_name: # Chosen flavor on target cloud - magnum_default_worker_flavor_name: # Chosen flavor on target cloud - magnum_external_net_name: # External network - magnum_loadbalancer_provider: # Octavia provider (e.g. 'ovn') + # Chosen flavor on target cloud + magnum_default_master_flavor_name: + # Chosen flavor on target cloud + magnum_default_worker_flavor_name: + # External network to use for load balancers etc. + magnum_external_net_name: + # Octavia provider (e.g. 'ovn') + magnum_loadbalancer_provider: + # Optional list of extra labels to add to all generated cluster templates + magnum_template_extra_labels: then run the provided playbook with diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..09460fd --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +bin_ansible_callbacks = True +callbacks_enabled = ansible.posix.profile_tasks +stdout_callback = yaml diff --git a/ansible/generate-magnum-capi-templates.yml b/ansible/generate-magnum-capi-templates.yml index ccbb574..45deec7 100644 --- a/ansible/generate-magnum-capi-templates.yml +++ b/ansible/generate-magnum-capi-templates.yml @@ -4,57 +4,59 @@ vars: root_dir: ../ tasks: - - - name: Check that required variables are defined - assert: - that: - - magnum_default_master_flavor_name is defined - - magnum_default_worker_flavor_name is defined - - magnum_external_net_name is defined - - magnum_loadbalancer_provider is defined - - - name: Fetch capi-helm-charts release information - ansible.builtin.uri: - url: https://api.github.com/repos/stackhpc/capi-helm-charts/releases/latest - register: capi_helm_chart_release_data - - - name: Fetch dependencies.json for capi-helm-charts release - ansible.builtin.uri: - url: https://raw.githubusercontent.com/stackhpc/capi-helm-charts/{{ capi_helm_chart_release_data.json.tag_name }}/dependencies.json - register: dependencies_response - - - name: Ensure wget packages is installed - become: true - package: - name: wget - state: present - - - name: Fetch manifest.json for capi-helm-charts images + - name: Check that required variables are defined + ansible.builtin.assert: + that: + - magnum_default_master_flavor_name is defined + - magnum_default_worker_flavor_name is defined + - magnum_external_net_name is defined + - magnum_loadbalancer_provider is defined + + - name: Fetch capi-helm-charts release information + ansible.builtin.uri: + url: https://api.github.com/repos/azimuth-cloud/capi-helm-charts/releases/latest + register: capi_helm_chart_release_data + + - name: Fetch dependencies.json for capi-helm-charts release + ansible.builtin.uri: + url: https://raw.githubusercontent.com/azimuth-cloud/capi-helm-charts/{{ capi_helm_chart_release_data.json.tag_name }}/dependencies.json + register: dependencies_response + + - name: Ensure wget packages is installed + become: true + ansible.builtin.package: + name: wget + state: present + + - name: Fetch manifest.json for capi-helm-charts images # noqa command-instead-of-module # ansible.builtin.uri: - # url: https://raw.githubusercontent.com/stackhpc/azimuth-images/{{ dependencies_response.json['azimuth-images'] }}/manifest.json + # url: https://raw.githubusercontent.com/azimuth-cloud/azimuth-images/{{ dependencies_response.json['azimuth-images'] }}/manifest.json # Above URL returns 404 even though similar URL for capi-helm-charts repo works fine # Not sure why but fall back to wget + JSON parsing for now. - shell: "wget -O - https://github.com/stackhpc/azimuth-images/releases/download/{{ dependencies_response.json['azimuth-images'] }}/manifest.json" - register: manifest_response - changed_when: false - - - name: Parse JSON response - set_fact: - new_template_data: "{{ manifest_response.stdout | from_json | dict2items | selectattr('key', 'match', 'kubernetes*') | list }}" - - - name: Ensure output dir exists - ansible.builtin.file: - path: "{{ [root_dir, 'generated-magnum-snippets', now(utc=true,fmt='%Y-%m-%d-T%H-%M-%S')] | path_join }}" - state: directory - mode: '0755' - register: output_dir - - - name: Write new image config to file - template: - src: "magnum-capi-images.j2" - dest: "{{ output_dir.path }}/images.yml" - - - name: Write new cluster template config to file - template: - src: "magnum-capi-templates.j2" - dest: "{{ output_dir.path }}/templates.yml" + ansible.builtin.command: >- + wget -O - https://github.com/azimuth-cloud/azimuth-images/releases/download/{{ dependencies_response.json['azimuth-images'] }}/manifest.json + register: manifest_response + changed_when: false + + - name: Parse JSON response + ansible.builtin.set_fact: + new_template_data: "{{ manifest_response.stdout | from_json | dict2items | selectattr('key', 'match', 'kubernetes*') | list }}" + + - name: Ensure output dir exists + ansible.builtin.file: + path: "{{ [root_dir, 'generated-magnum-snippets', now(utc=true, fmt='%Y-%m-%d-T%H-%M-%S')] | path_join }}" + state: directory + mode: "0755" + register: output_dir + + - name: Write new image config to file + ansible.builtin.template: + src: "magnum-capi-images.j2" + dest: "{{ output_dir.path }}/images.yml" + mode: "0644" + + - name: Write new cluster template config to file + ansible.builtin.template: + src: "magnum-capi-templates.j2" + dest: "{{ output_dir.path }}/templates.yml" + mode: "0644" diff --git a/ansible/group_vars/all/openstack b/ansible/group_vars/all/openstack index 462f3eb..3d9cb8d 100644 --- a/ansible/group_vars/all/openstack +++ b/ansible/group_vars/all/openstack @@ -62,3 +62,26 @@ openstack_host_aggregates: [] # List of clusters templates in the openstack project. Format is as required by the # stackhpc.os-container-clusters role. openstack_container_clusters_templates: [] + +############################################################################### +# Configuration variables for a CloudKitty ratings service deployment. + +# A list where each item is a dictionary mapping the associated fields, +# with the 'mappings' field also being a list of dictionaries. +# Example of the mappings and their fields can be found below, +# however for more information please refer to the README.md file. +# +openstack_ratings_hashmap_field_mappings: [] + +# Much like the field mappings above, the service mappings are a list of +# dictionaries, however these are not associated with a field. +# +openstack_ratings_hashmap_service_mappings: [] + +############################################################################### +# Configuration of volumes for OpenStack. +openstack_volumes_types: [] + +############################################################################### +# Configuration of Cloudkitty for OpenStack. +openstack_cloudkitty_enable: false diff --git a/ansible/openstack-ratings.yml b/ansible/openstack-ratings.yml new file mode 100644 index 0000000..bef3713 --- /dev/null +++ b/ansible/openstack-ratings.yml @@ -0,0 +1,10 @@ +--- +- name: Generate OpenStack software ratings + hosts: localhost + tags: + - ratings + roles: + - role: stackhpc.openstack.os_ratings + os_ratings_hashmap_field_mappings: "{{ openstack_ratings_hashmap_field_mappings }}" + os_ratings_hashmap_service_mappings: "{{ openstack_ratings_hashmap_service_mappings }}" + os_ratings_venv: "{{ openstack_venv }}" diff --git a/ansible/openstack-volume-types.yml b/ansible/openstack-volume-types.yml new file mode 100644 index 0000000..be1248a --- /dev/null +++ b/ansible/openstack-volume-types.yml @@ -0,0 +1,12 @@ +--- +- name: Ensure OpenStack volume types exist + hosts: localhost + tags: + - volume-types + roles: + - role: stackhpc.openstack.os_volumes + os_volumes_venv: "{{ openstack_venv }}" + os_volumes_auth_type: "{{ openstack_auth_type }}" + os_volumes_auth: "{{ openstack_auth }}" + os_volumes_cacert: "{{ openstack_cacert }}" + os_volumes_types: "{{ openstack_volumes_types }}" diff --git a/ansible/openstack.yml b/ansible/openstack.yml index cfaf612..56beb10 100644 --- a/ansible/openstack.yml +++ b/ansible/openstack.yml @@ -1,8 +1,12 @@ --- # Top level playbook that includes all others. -- import_playbook: openstack-project.yml -- import_playbook: openstack-networks.yml -- import_playbook: openstack-flavors.yml -- import_playbook: openstack-images.yml -- import_playbook: openstack-host-aggregates.yml -- import_playbook: openstack-container-clusters.yml + +- import_playbook: openstack-project.yml # noqa name[play] +- import_playbook: openstack-networks.yml # noqa name[play] +- import_playbook: openstack-flavors.yml # noqa name[play] +- import_playbook: openstack-images.yml # noqa name[play] +- import_playbook: openstack-host-aggregates.yml # noqa name[play] +- import_playbook: openstack-volume-types.yml # noqa name[play] +- import_playbook: openstack-container-clusters.yml # noqa name[play] +- import_playbook: openstack-ratings.yml # noqa name[play] + when: openstack_cloudkitty_enable | bool diff --git a/ansible/templates/magnum-capi-images.j2 b/ansible/templates/magnum-capi-images.j2 index 2e5e7e2..366b299 100644 --- a/ansible/templates/magnum-capi-images.j2 +++ b/ansible/templates/magnum-capi-images.j2 @@ -15,10 +15,10 @@ name: "{{ item.value.name }}" type: qcow2 image_url: "{{ item.value.url }}" - visibility: "community" + visibility: "public" properties: os_distro: "ubuntu" - os_version: "20.04" + os_version: "22.04" kube_version: "{{ item.value.kubernetes_version }}" {% endfor %} diff --git a/ansible/templates/magnum-capi-templates.j2 b/ansible/templates/magnum-capi-templates.j2 index 65c5c7a..a555b1d 100644 --- a/ansible/templates/magnum-capi-templates.j2 +++ b/ansible/templates/magnum-capi-templates.j2 @@ -16,6 +16,9 @@ keystone_auth_enabled: "false" capi_helm_chart_version: "{{ capi_helm_chart_release_data.json.tag_name }}" octavia_provider: {{ magnum_loadbalancer_provider }} +{% if magnum_template_extra_labels is defined and magnum_template_extra_labels is not none %} + {{ magnum_template_extra_labels | to_nice_yaml | indent(4) -}} +{% endif %} external_network_id: {{ magnum_external_net_name }} master_flavor: {{ magnum_default_master_flavor_name }} flavor: {{ magnum_default_worker_flavor_name }} @@ -28,4 +31,4 @@ dns_nameserver: "{{ (magnum_cluster_default_dns_nameservers | default(['1.1.1.1', '8.8.8.8', '8.8.4.4'])) | join(',') }}" public: "{{ magnum_cluster_templates_public | default('True') }}" -{% endfor %} \ No newline at end of file +{% endfor %} diff --git a/etc/openstack-config/openstack-config.yml b/etc/openstack-config/openstack-config.yml index 2513797..73a1605 100644 --- a/etc/openstack-config/openstack-config.yml +++ b/etc/openstack-config/openstack-config.yml @@ -4,11 +4,11 @@ # List of OpenStack domains. Format is as required by the stackhpc.os-projects # role. -#openstack_domains: +# openstack_domains: # List of OpenStack projects. Format is as required by the stackhpc.os-projects # role. -#openstack_projects: +# openstack_projects: ############################################################################### # Configuration of networks, subnets and routers for openstack. @@ -145,7 +145,7 @@ openstack_security_groups: # List of RBAC definitions in the openstack projct. Format is as required by the # stackhpc.os-networks role. -#openstack_networks_rbac: +# openstack_networks_rbac: ############################################################################### # Configuration of nova flavors. @@ -195,7 +195,7 @@ openstack_flavor_m1_xlarge: # List of nova host aggregates. Format is as required by the # stackhpc.os_host_aggregates role. -#openstack_host_aggregates: +# openstack_host_aggregates: ############################################################################### # Configuration of Glance software images. @@ -208,7 +208,7 @@ openstack_image_cirros_0_6_0: name: "cirros" type: qcow2 image_url: "https://github.com/cirros-dev/cirros/releases/download/0.6.0/cirros-0.6.0-x86_64-disk.img" - is_public: True + is_public: true properties: os_type: "linux" os_distro: "cirros" @@ -216,18 +216,18 @@ openstack_image_cirros_0_6_0: hw_rng_model: "virtio" # List of Diskimage Builder (DIB) elements paths to include in image builds. -#openstack_image_elements: +# openstack_image_elements: # List of Diskimage Builder (DIB) elements Git repositories to use in image # builds. -#openstack_image_git_elements: +# openstack_image_git_elements: ############################################################################### # Configuration of Magnum container clusters. # List of magnum cluster templates. Format is as required by the # stackhpc.os-container-clusters role. -#openstack_container_clusters_templates: +# openstack_container_clusters_templates: ############################################################################### # Configuration variables for generating new Magnum cluster template config. @@ -261,3 +261,38 @@ openstack_image_cirros_0_6_0: # Whether generated cluster templates should be public by default (defaults to 'True') # magnum_cluster_templates_public: + +############################################################################### +# Configuration variables for a CloudKitty ratings service deployment. + +# # ### ####### ##### IN ORDER TO SUCCESSFULLY DEPLOY CLOUDKITTY +# # # # # # # 'cloudkitty.conf' & 'metrics.yml' MUST BE +# # # # # # ### PROVIDED ALONGSIDE THE FOLLOWING CONFIG. +# # # # # # # MORE INFO CAN BE FOUND IN THE README.md +# # ### # ##### 'stackhpc-kayobe-config' DOCS. +# A list where each item is a dictionary mapping the associated fields, +# with the 'mappings' field also being a list of dictionaries. Example +# of the mappings and their fields can be found below, however for more +# information please refer to the stackhpc.openstack.os_ratings role docs. +# +# openstack_ratings_hashmap_field_mappings: +# - service: SERVICE_NAME +# name: FIELD_NAME +# mappings: +# - value: MAPPING_VALUE +# cost: MAPPING_COST +# type: MAPPING_TYPE +# group: MAPPING_GROUP <---THIS IS OPTIONAL--- + +# Much like the field mappings above, the service mappings are a list of +# dictionaries, however these are not associated with a field. +# +# openstack_ratings_hashmap_service_mappings: +# - service: SERVICE_NAME +# cost: MAPPING_COST +# type: MAPPING_TYPE +# group: MAPPING_GROUP <---THIS IS OPTIONAL--- + +############################################################################### +# Dummy variable to allow Ansible to accept this file. +workaround_ansible_issue_8743: true diff --git a/examples/container-clusters.yml b/examples/container-clusters.yml index 4d85d20..a4af4aa 100644 --- a/examples/container-clusters.yml +++ b/examples/container-clusters.yml @@ -9,7 +9,7 @@ openstack_container_clusters_templates: # Kubernetes magnum cluster template. openstack_container_clusters_template_k8s_fedora_coreos: - labels: "heat_container_agent_tag=ussuri-stable-1,kube_tag=v1.18.9,cloud_provider_tag=v1.18.2,monitoring_enabled=true,auto_scaling_enabled=true,auto_healing_enabled=true,auto_healing_controller=magnum-auto-healer,magnum_auto_healer_tag=latest,master_lb_floating_ip_enabled=true,cinder_csi_enabled=true,ingress_controller=octavia" + labels: "heat_container_agent_tag=ussuri-stable-1,kube_tag=v1.18.9,cloud_provider_tag=v1.18.2,monitoring_enabled=true,auto_scaling_enabled=true,auto_healing_enabled=true,auto_healing_controller=magnum-auto-healer,magnum_auto_healer_tag=latest,master_lb_floating_ip_enabled=true,cinder_csi_enabled=true,ingress_controller=octavia" # noqa yaml[line-length] external-network: "external" master-flavor: "m1.medium" flavor: "m1.medium" diff --git a/examples/images.yml b/examples/images.yml index 925406c..1baf7a5 100644 --- a/examples/images.yml +++ b/examples/images.yml @@ -20,6 +20,11 @@ openstack_images: - "{{ openstack_image_rocky8 }}" - "{{ openstack_image_ubuntu_focal }}" +# Common GRUB settings for VM images +openstack_grub_env_common: + DIB_GRUB_TIMEOUT: 0 + DIB_GRUB_TIMEOUT_STYLE: hidden + # CentOS Stream 8. openstack_image_centos_stream8: name: "CentOS-stream8" @@ -34,7 +39,7 @@ openstack_image_centos_stream8: - "vm" - "grub2" - "stable-interface-names" - is_public: True + is_public: true env: YUM: dnf DIB_RELEASE: "8-stream" @@ -55,7 +60,7 @@ openstack_image_cirros_0_6_0: type: qcow2 image_url: "https://github.com/cirros-dev/cirros/releases/download/0.6.0/cirros-0.6.0-x86_64-disk.img" checksum: "md5:f4027b89e99e238184e13089a3155b74" - is_public: True + is_public: true properties: os_type: "linux" os_distro: "cirros" @@ -78,7 +83,7 @@ openstack_image_rocky8: - "grub2" - "stable-interface-names" - "openssh-server" - is_public: True + is_public: true packages: - "bash-completion" - "vim-enhanced" @@ -101,7 +106,7 @@ openstack_image_rocky8: openstack_image_ubuntu_focal: name: "Ubuntu-20.04" type: raw - is_public: True + is_public: true elements: # Required for UEFI mode: - "block-device-efi" diff --git a/examples/networks.yml b/examples/networks.yml index f6e6c12..38e769c 100644 --- a/examples/networks.yml +++ b/examples/networks.yml @@ -125,12 +125,16 @@ openstack_router_demo: # List of security groups in the openstack demo project. # Format is as required by the stackhpc.os-networks role. openstack_security_groups: - # Default security group for the openstack demo project. - - name: default + # ICMP security group for the openstack demo project. + - name: ICMP project: demo rules: # Allow ICMP (for ping, etc.). - protocol: icmp + # SSH security group for the openstack demo project. + - name: SSH + project: demo + rules: # Allow SSH. - protocol: tcp port_range_min: 22 diff --git a/examples/projects-octavia.yml b/examples/projects-octavia.yml index f116b18..af40422 100644 --- a/examples/projects-octavia.yml +++ b/examples/projects-octavia.yml @@ -27,3 +27,4 @@ openstack_octavia_unlimited_quotas: ram: -1 security_group: -1 security_group_rule: -1 + server-groups: -1 diff --git a/examples/ratings.yml b/examples/ratings.yml new file mode 100644 index 0000000..9a1d35a --- /dev/null +++ b/examples/ratings.yml @@ -0,0 +1,48 @@ +--- +############################################################################### +# Configuration of CloudKitty for openstack. + +# Example configuration for registering CloudKitty fields. +# Included is mapping for various different compute flavors & +# a service mapping based on the stored image size in Glance. + +openstack_ratings_hashmap_field_mappings: + - service: instance + name: flavor_id + mappings: + - value: "1" # tiny compute flavour with an OpenStack flavor ID of 1 + cost: 1.0 + group: instance_uptime_flavor_id + type: flat + - value: "2" # small compute flavour with an OpenStack flavor ID of 2 + cost: 2.0 + group: instance_uptime_flavor_id + type: flat + - value: "3" # medium compute flavour with an OpenStack flavor ID of 3 + cost: 3.0 + group: instance_uptime_flavor_id + type: flat + - value: "4" # large compute flavour with an OpenStack flavor ID of 4 + cost: 4.0 + group: instance_uptime_flavor_id + type: flat + - value: "5" # xlarge compute flavour with an OpenStack flavor ID of 5 + cost: 5.0 + group: instance_uptime_flavor_id + type: flat + - value: "6" # tiny 2 compute flavour with an OpenStack flavor ID of 6 + cost: 2.0 + group: instance_uptime_flavor_id + type: flat + +openstack_ratings_hashmap_service_mappings: + - service: image.size + cost: 0.1 + group: image_size + type: flat + +# # ### ####### ##### THIS CONFIGURATION FILE ONLY WORKS IF +# # # # # # # 'cloudkitty.conf' & 'metrics.yml' ARE +# # # # # # ### CONFIGURED CORRECTLY. MORE INFO CAN +# # # # # # # BE FOUND IN THE 'stackhpc-kayobe-config' +# # ### # ##### DOCS. diff --git a/examples/volume-types.yml b/examples/volume-types.yml new file mode 100644 index 0000000..704e7ae --- /dev/null +++ b/examples/volume-types.yml @@ -0,0 +1,21 @@ +--- +############################################################################### +# Configuration of volume types for openstack. + +# List of volume types. Format is as required by the stackhpc.os-volumes role. +openstack_volumes_types: + - "{{ openstack_volume_type_ceph_hdd }}" + - "{{ openstack_volume_type_ceph_ssd }}" + +# Volume types +openstack_volume_type_ceph_hdd: + name: "ceph-hdd" + description: "Ceph HDD pool" + extra_specs: + volume_backend_name: "replicated-hdd" + +openstack_volume_type_ceph_ssd: + name: "ceph-ssd" + description: "Ceph SSD pool" + extra_specs: + volume_backend_name: "replicated-ssd" diff --git a/requirements.txt b/requirements.txt index 0c0c0b4..e4abdb9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ # Use Ansible 5 for consistent Rocky 9 behaviour when available, otherwise use # Ansible 4 ansible>=4,<5; python_version<"3.7" -ansible>=5,<6; python_version>="3.7" +ansible>=5,<6; python_version>="3.7" and python_version<"3.9" +ansible>=8,<10; python_version>="3.9" and python_version<"3.12" +ansible>=10,<11; python_version>="3.12" diff --git a/requirements.yml b/requirements.yml index e7f338a..c58c0ae 100644 --- a/requirements.yml +++ b/requirements.yml @@ -1,6 +1,6 @@ --- collections: - name: openstack.cloud - version: 2.1.0 + version: 2.4.1 - name: stackhpc.openstack - version: 0.1.1 + version: 0.2.4