├── ansible.cfg ├── playbooks ├── templates │ ├── env.sh.j2 │ ├── standalone_snat.service.j2 │ ├── sshuttle-standalone.sh.j2 │ ├── standalone_parameters.ceph_ansible.yaml.j2 │ ├── dev-install_net_config_dpdk.yaml.j2 │ ├── dev-install_net_config.yaml.j2 │ └── standalone_parameters.yaml.j2 ├── roles │ ├── simpleca │ │ ├── defaults │ │ │ └── main.yml │ │ └── tasks │ │ │ └── main.yaml │ ├── tripleo_module_load │ │ ├── templates │ │ │ └── module-load.conf.j2 │ │ ├── meta │ │ │ └── main.yml │ │ ├── defaults │ │ │ └── main.yml │ │ └── tasks │ │ │ └── main.yml │ ├── rhsm │ │ └── tasks │ │ │ └── main.yaml │ ├── snat │ │ └── tasks │ │ │ └── main.yaml │ ├── tuned │ │ ├── vars │ │ │ └── redhat.yml │ │ ├── tasks │ │ │ ├── tuned_install.yml │ │ │ ├── main.yml │ │ │ └── tuned_config.yml │ │ ├── defaults │ │ │ └── main.yml │ │ └── meta │ │ │ └── main.yml │ ├── tripleo_ovs_dpdk │ │ ├── tasks │ │ │ ├── main.yml │ │ │ ├── workarounds.yml │ │ │ └── config.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── defaults │ │ │ └── main.yml │ │ └── library │ │ │ └── openvswitch_db.py │ ├── tripleo_kernel │ │ ├── defaults │ │ │ └── main.yml │ │ └── tasks │ │ │ ├── reboot.yaml │ │ │ └── kernelargs.yml │ ├── operators │ │ └── tasks │ │ │ └── main.yaml │ ├── ceph │ │ └── tasks │ │ │ ├── storage-network.yml │ │ │ └── main.yaml │ └── network_info │ │ └── tasks │ │ └── main.yaml ├── local_requirements.yaml ├── certs.yaml ├── post_install.yaml ├── files │ ├── cloud-to-env.py │ └── export-dcn.sh ├── destroy.yaml ├── prepare_stack_testconfig.yaml ├── local_os_client.yaml ├── network.yaml ├── vars │ └── defaults.yaml ├── prepare_stack.yaml ├── prepare_host.yaml └── install_stack.yaml ├── requirements.yaml ├── example-overrides ├── local-overrides-centos8-tripleo-master.yaml ├── local-overrides-centos9-tripleo-master.yaml ├── local-overrides-osp17-1-with-sriov.yaml ├── local-overrides-centos8-tripleo-train.yaml ├── local-overrides-osp17-1-with-sriov-and-dpdk.yaml ├── local-overrides-basic.yaml ├── local-overrides-rhel8_2-tripleo-osp16-1.yaml ├── local-overrides-rhel8_4-tripleo-osp16-2.yaml └── local-overrides-osp17-1-with-dpdk.yaml ├── .gitignore ├── .github └── workflows │ └── ansible-lint.yml ├── .ansible-lint ├── Makefile └── README.md /ansible.cfg: -------------------------------------------------------------------------------- 1 | [ssh_connection] 2 | pipelining = true 3 | -------------------------------------------------------------------------------- /playbooks/templates/env.sh.j2: -------------------------------------------------------------------------------- 1 | export OS_CLOUD={{ local_cloudname }} 2 | -------------------------------------------------------------------------------- /playbooks/roles/simpleca/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | cert_dir: .. 3 | ca_dir: "{{ cert_dir }}/simpleca" 4 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_module_load/templates/module-load.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | {{ item.name }} {{ item.params |default('') }} 3 | -------------------------------------------------------------------------------- /requirements.yaml: -------------------------------------------------------------------------------- 1 | collections: 2 | - ansible.posix 3 | - community.general 4 | - tripleo.operator 5 | - containers.podman 6 | - community.crypto 7 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-centos8-tripleo-master.yaml: -------------------------------------------------------------------------------- 1 | standalone_host: 2 | public_api: 3 | tripleo_repos_repos: 4 | - current-tripleo-dev 5 | - ceph 6 | -------------------------------------------------------------------------------- /playbooks/local_requirements.yaml: -------------------------------------------------------------------------------- 1 | - hosts: localhost 2 | connection: local 3 | vars: 4 | update_operator: true 5 | update_rhsm: true 6 | name: Deploy local requirements 7 | roles: 8 | - operators 9 | - rhsm 10 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-centos9-tripleo-master.yaml: -------------------------------------------------------------------------------- 1 | standalone_host: 2 | public_api: 3 | tripleo_repos_repo_branch: master 4 | cip_config: 5 | - set: 6 | namespace: quay.io/tripleomastercentos9 7 | name_prefix: openstack- 8 | tag: current-tripleo 9 | -------------------------------------------------------------------------------- /playbooks/certs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | name: Deploy the CA 4 | gather_facts: false 5 | vars_files: vars/defaults.yaml 6 | roles: 7 | - name: Deploy the CA with the simplaca role 8 | role: simpleca 9 | vars: 10 | cert_user: quay 11 | cert_name: "{{ standalone_host }}" 12 | -------------------------------------------------------------------------------- /playbooks/post_install.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: stack 5 | gather_facts: false 6 | name: Run post-install 7 | tasks: 8 | - name: Run post-install script # noqa no-changed-when command-instead-of-shell 9 | ansible.builtin.shell: "{{ post_install }}" 10 | when: post_install is defined 11 | -------------------------------------------------------------------------------- /playbooks/templates/standalone_snat.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Add SNAT rule for public network 3 | After=network-online.target 4 | 5 | [Service] 6 | Type=oneshot 7 | ExecStart=/usr/sbin/iptables -t nat -A POSTROUTING -s {{ cidr }} -o {{ exit_nic }} -j SNAT --to {{ exit_ip }} 8 | RemainAfterExit=true 9 | StandardOutput=journal 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-osp17-1-with-sriov.yaml: -------------------------------------------------------------------------------- 1 | sriov_interface: enp130s0f0 2 | sriov_nova_pci_passthrough: 3 | - devname: "enp130s0f0" 4 | physical_network: "hostonly-sriov" 5 | sriov_nic_numvfs: 63 6 | kernel_args: "default_hugepagesz=1GB hugepagesz=1G hugepages=128 iommu=pt intel_iommu=on isolcpus=4-47" 7 | tuned_isolated_cores: "4-47" 8 | extra_heat_params: 9 | NovaComputeCpuDedicatedSet: ['6-47'] 10 | NovaComputeCpuSharedSet: [0,1,2,3] 11 | -------------------------------------------------------------------------------- /playbooks/templates/sshuttle-standalone.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | remote=root@{{ standalone_host }} 4 | 5 | pidfile=/run/sshuttle-standalone-${USER}.pid 6 | [ -r "${pidfile}" ] && pid=$(cat "${pidfile}") 7 | 8 | exec sudo --preserve-env=SSH_AUTH_SOCK,SSH_AGENT_PID -- sh -c " 9 | [ ! -z \"${pid}\" ] && /usr/bin/kill ${pid} 10 | sshuttle --pidfile=\"${pidfile}\" -D --dns \ 11 | -r \"${remote}\" {{ hostonly_cidr }} >/dev/null 2>&1 12 | " 13 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-centos8-tripleo-train.yaml: -------------------------------------------------------------------------------- 1 | standalone_host: 2 | public_api: 3 | tripleo_repos_branch: train 4 | # tripleo-repos only supports --stream (for CentOS 8 Stream) after Train, 5 | # so we need to pull tripleo-repos tool from master and move on. 6 | tripleo_repos_repo_branch: master 7 | cip_config: 8 | - set: 9 | namespace: quay.io/tripleotraincentos8 10 | name_prefix: centos-binary- 11 | tag: current-tripleo 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /inventory.yaml 2 | /local-overrides* 3 | /scripts/env.sh 4 | /scripts/sshuttle-standalone.sh 5 | /simpleca 6 | /quay.crt 7 | /quay.csr 8 | /quay.key 9 | 10 | # From https://github.com/github/gitignore/blob/master/Global/Vim.gitignore 11 | # Swap 12 | [._]*.s[a-v][a-z] 13 | #!*.svg # comment out if you don't need vector files 14 | [._]*.sw[a-p] 15 | [._]s[a-rt-v][a-z] 16 | [._]ss[a-gi-z] 17 | [._]sw[a-p] 18 | 19 | # Session 20 | Session.vim 21 | Sessionx.vim 22 | 23 | # Temporary 24 | .netrwhist 25 | *~ 26 | # Auto-generated tag files 27 | tags 28 | # Persistent undo 29 | [._]*.un~ 30 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-osp17-1-with-sriov-and-dpdk.yaml: -------------------------------------------------------------------------------- 1 | sriov_interface: enp130s0f0 2 | sriov_nova_pci_passthrough: 3 | - devname: "enp130s0f0" 4 | physical_network: "hostonly-sriov" 5 | sriov_nic_numvfs: 63 6 | dpdk_interface: enp130s0f1 7 | kernel_args: "default_hugepagesz=1GB hugepagesz=1G hugepages=128 iommu=pt intel_iommu=on isolcpus=4-47" 8 | tuned_isolated_cores: "4-47" 9 | extra_heat_params: 10 | NovaComputeCpuDedicatedSet: ['6-47'] 11 | NovaReservedHostMemory: 4096 12 | NovaComputeCpuSharedSet: [0,1,2,3] 13 | OvsDpdkSocketMemory: "2048,2048" 14 | OvsPmdCoreList: "4,5" 15 | -------------------------------------------------------------------------------- /playbooks/roles/rhsm/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure we have ~/.ansible 3 | tags: 4 | - always 5 | - lab 6 | ansible.builtin.file: 7 | mode: '755' 8 | path: ~/.ansible/roles 9 | state: directory 10 | 11 | - name: Clone ansible-role-redhat-subscription 12 | ansible.builtin.git: 13 | dest: ~/.ansible/roles/redhat-subscription 14 | repo: https://opendev.org/openstack/ansible-role-redhat-subscription 15 | update: "{{ update_rhsm | bool }}" 16 | # Upstream repo has been retired, this is the latest commit 17 | version: eefe5019238a7b88bda0a9df1a6d9b02267e4902 18 | -------------------------------------------------------------------------------- /playbooks/files/cloud-to-env.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import itertools 4 | import json 5 | import os 6 | import yaml 7 | 8 | def cloud_to_env(d): 9 | return itertools.chain.from_iterable( 10 | cloud_to_env(v) if isinstance(v, dict) 11 | else (("OS_%s" % k.upper(), v),) 12 | for k, v in d.items()) 13 | 14 | with open("%s/.config/openstack/clouds.yaml" % os.environ['HOME']) as f: 15 | clouds = yaml.safe_load(f) 16 | 17 | os_cloud=os.environ['OS_CLOUD'] 18 | cloud=clouds['clouds'][os_cloud] 19 | env_vars=dict(cloud_to_env(cloud)) 20 | print(json.dumps(env_vars)) 21 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-basic.yaml: -------------------------------------------------------------------------------- 1 | # A sample local-overrides.yaml that configures a "basic" deployment. 2 | # The default services are enabled and an external network is created, allowing 3 | # for e.g. SSH access to guests. Note that IP addresses are clearly deployment 4 | # specific and should be updated to reflect your environment. 5 | standalone_host: openstack.example.com 6 | ceph_devices: 7 | - /dev/sdb 8 | external_cidr: 10.1.10.2/24 9 | external_fip_pool_start: 10.1.10.100 10 | external_fip_pool_end: 10.1.10.104 11 | external_gateway: 10.1.10.254 12 | public_api: 10.1.240.48 13 | local_cloudname: example-cloud 14 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-rhel8_2-tripleo-osp16-1.yaml: -------------------------------------------------------------------------------- 1 | standalone_host: 2 | public_api: 3 | rhsm_repos: 4 | - rhel-8-for-x86_64-baseos-eus-rpms 5 | - rhel-8-for-x86_64-appstream-eus-rpms 6 | - rhel-8-for-x86_64-highavailability-eus-rpms 7 | - ansible-2.9-for-rhel-8-x86_64-rpms 8 | - openstack-16.1-for-rhel-8-x86_64-rpms 9 | - fast-datapath-for-rhel-8-x86_64-rpms 10 | - advanced-virt-for-rhel-8-x86_64-rpms 11 | - rhceph-4-tools-for-rhel-8-x86_64-rpms 12 | rhsm_method: "portal" 13 | rhsm_release: 8.2 14 | rhsm_container_tools_version: '2.0' 15 | virt_release: 8.2 16 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-rhel8_4-tripleo-osp16-2.yaml: -------------------------------------------------------------------------------- 1 | standalone_host: 2 | public_api: 3 | virt_release: 8.4 4 | rhsm_repos: 5 | - advanced-virt-for-rhel-8-x86_64-rpms 6 | - ansible-2.9-for-rhel-8-x86_64-rpms 7 | - fast-datapath-for-rhel-8-x86_64-rpms 8 | - openstack-16.2-for-rhel-8-x86_64-rpms 9 | - rhceph-4-tools-for-rhel-8-x86_64-rpms 10 | - rhel-8-for-x86_64-appstream-eus-rpms 11 | - rhel-8-for-x86_64-baseos-eus-rpms 12 | - rhel-8-for-x86_64-highavailability-eus-rpms 13 | rhsm_method: "portal" 14 | rhsm_release: 8.4 15 | rhsm_container_tools_version: '3.0' 16 | -------------------------------------------------------------------------------- /.github/workflows/ansible-lint.yml: -------------------------------------------------------------------------------- 1 | name: Ansible Lint 2 | on: 3 | pull_request: 4 | paths: 5 | - playbooks/**.yaml 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | 11 | - name: Checks-out the repository under $GITHUB_WORKSPACE 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | 16 | - name: Install ansible-lint 17 | run: python3 -m pip install ansible-dev-tools --user 18 | 19 | - name: Install dependency 20 | run: ansible-galaxy collection install -r requirements.yaml 21 | 22 | - name: Run lint 23 | run: ansible-lint playbooks/** 24 | -------------------------------------------------------------------------------- /playbooks/roles/snat/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "Create systemd unit to add SNAT rule for network {{ network_name }}" 4 | ansible.builtin.template: 5 | src: "standalone_snat.service.j2" 6 | dest: "/etc/systemd/system/standalone_{{ network_name }}_snat.service" 7 | owner: root 8 | group: root 9 | mode: '644' 10 | vars: 11 | cidr: "{{ network_cidr }}" 12 | exit_ip: "{{ public_ip }}" 13 | exit_nic: "{{ public_nic }}" 14 | 15 | - name: Activate systemd units 16 | ansible.builtin.systemd: 17 | name: "standalone_{{ network_name }}_snat.service" 18 | enabled: true 19 | state: started 20 | daemon_reload: true 21 | -------------------------------------------------------------------------------- /playbooks/roles/tuned/vars/redhat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | _tuned_system_packages: 18 | - tuned 19 | - tuned-profiles-cpu-partitioning 20 | -------------------------------------------------------------------------------- /playbooks/templates/standalone_parameters.ceph_ansible.yaml.j2: -------------------------------------------------------------------------------- 1 | #vi:syntax=yaml 2 | 3 | CephPoolDefaultPgNum: 8 4 | CephPoolDefaultSize: 1 5 | CephSpecFqdn: true 6 | 7 | {% if ceph_devices is defined %} 8 | CephAnsibleDisksConfig: 9 | osd_scenario: lvm 10 | osd_objectstore: bluestore 11 | devices: 12 | {% for device in ceph_devices %} 13 | - {{ device }} 14 | {% endfor %} 15 | {% else %} 16 | CephAnsibleDisksConfig: 17 | osd_scenario: lvm 18 | osd_objectstore: bluestore 19 | lvm_volumes: 20 | - data: data 21 | data_vg: vg_ceph 22 | db: db 23 | db_vg: vg_ceph 24 | {% endif %} 25 | CephAnsibleExtraConfig: 26 | cluster_network: {{ control_plane_cidr }} 27 | public_network: {{ control_plane_cidr }} 28 | {% if manila_enabled %} 29 | ceph_nfs_bind_addr: "{{ public_api }}" 30 | {% endif %} 31 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_ovs_dpdk/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | - ansible.builtin.include_tasks: config.yml 18 | 19 | - name: Enable DPDK 20 | openvswitch_db: 21 | table: open_vswitch 22 | record: . 23 | col: other_config 24 | key: dpdk-init 25 | value: "true" 26 | timeout: 300 27 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_kernel/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | # All variables intended for modification should be placed in this file. 19 | tripleo_kernel_args: "" 20 | tripleo_kernel_reboot_timeout: 3600 21 | tripleo_kernel_post_reboot_delay: 60 22 | tripleo_kernel_defer_reboot: false 23 | tripleo_kernel_reboot_protection: false 24 | -------------------------------------------------------------------------------- /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | # .ansible-lint 3 | 4 | exclude_paths: 5 | # these roles were copy/pasted from tripleo 6 | - playbooks/roles/tripleo_kernel 7 | - playbooks/roles/tripleo_module_load 8 | - playbooks/roles/tripleo_ovs_dpdk 9 | - playbooks/roles/tuned 10 | 11 | mock_modules: 12 | - community.crypto.openssl_csr 13 | - community.crypto.openssl_privatekey 14 | - community.crypto.x509_certificate 15 | - community.general.filesystem 16 | - community.general.ini_file 17 | - community.general.lvg 18 | - community.general.lvol 19 | - community.general.modprobe 20 | 21 | mock_roles: 22 | - redhat-subscription 23 | - tripleo.operator.tripleo_deploy 24 | - tripleo.operator.tripleo_repos 25 | - tripleo.operator.tripleo_container_image_prepare_default 26 | 27 | skip_list: 28 | # Variables names from within roles should use role_name_ as a prefix 29 | - var-naming[no-role-prefix] 30 | - key-order[play] 31 | - fqcn[action-core] 32 | - var-naming[no-reserved] 33 | -------------------------------------------------------------------------------- /playbooks/roles/tuned/tasks/tuned_install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | - name: Install tuned 19 | become: true 20 | package: 21 | name: "{{ tuned_system_packages }}" 22 | state: present 23 | register: _tuned_install_result 24 | 25 | - name: Restart tuned # noqa no-handler 26 | become: true 27 | ansible.builtin.systemd: 28 | name: tuned 29 | state: restarted 30 | enabled: true 31 | when: 32 | - _tuned_install_result.changed 33 | -------------------------------------------------------------------------------- /playbooks/roles/tuned/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | # All variables intended for modification should be placed in this file. 19 | 20 | tuned_profile: "throughput-performance" 21 | tuned_custom_profile: "" 22 | tuned_isolated_cores: "" 23 | 24 | # Packages installed on the local system. Allows user to define this list 25 | # otherwise it will inherit from the OS specific variable file(s). 26 | tuned_system_packages: "{{ _tuned_system_packages | default([]) }}" 27 | -------------------------------------------------------------------------------- /example-overrides/local-overrides-osp17-1-with-dpdk.yaml: -------------------------------------------------------------------------------- 1 | standalone_host: 2 | public_api: 3 | 4 | # PCIPassthrough example for device " 0b:00.0 VGA compatible controller [0300]: Matrox Electronics Systems Ltd. G200eR2 [102b:0534] (rev 01)" 5 | # For available device_type values see https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/16.1/html/configuring_the_compute_service_for_instance_creation/configuring-pci-passthrough 6 | standalone_extra_config: 7 | nova::pci::aliases: 8 | - name: "VGAalias" 9 | vendor_id: "102b" 10 | product_id: "0534" 11 | device_type: "type-PCI" 12 | 13 | extra_heat_params: 14 | NovaSchedulerDefaultFilters: ['RetryFilter','AvailabilityZoneFilter','ComputeFilter','ComputeCapabilitiesFilter','ImagePropertiesFilter','ServerGroupAntiAffinityFilter','ServerGroupAffinityFilter','PciPassthroughFilter','NUMATopologyFilter'] 15 | NovaSchedulerAvailableFilters: ["nova.scheduler.filters.all_filters","nova.scheduler.filters.pci_passthrough_filter.PciPassthroughFilter"] 16 | NovaPCIPassthrough: 17 | - vendor_id: "102b" 18 | product_id: "0534" 19 | 20 | kernel_args: "iommu=pt intel_iommu=on" 21 | -------------------------------------------------------------------------------- /playbooks/destroy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: root 5 | gather_facts: false 6 | vars_files: vars/defaults.yaml 7 | name: Destroy the OpenStack 8 | tasks: 9 | - name: Run the command to destroy the OpenStack # noqa no-changed-when 10 | ansible.builtin.shell: | 11 | pkill -9 heat-all 12 | if type pcs &> /dev/null; then 13 | pcs cluster destroy 14 | fi 15 | if type podman &> /dev/null; then 16 | podman rm -af 17 | podman rmi -af 18 | fi 19 | rm -rf \ 20 | /var/lib/tripleo-config \ 21 | /var/lib/config-data /var/lib/container-config-scripts \ 22 | /var/lib/container-puppet \ 23 | /var/lib/heat-config \ 24 | /var/lib/ceph \ 25 | /var/lib/image-serve \ 26 | /etc/systemd/system/tripleo* \ 27 | /var/lib/mysql/* \ 28 | /etc/openstack/ \ 29 | /home/stack/.config/openstack 30 | systemctl daemon-reload 31 | # Don't cleanup containers. It's basically just a cache and re-downloading 32 | # it dominates reinstallation time. 33 | # /var/lib/containers 34 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_ovs_dpdk/tasks/workarounds.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | # Workaround to allow access of vhostuser sockets from OvS running host to qemu 18 | # running inside the kolla container. GID of the group 'hugetlbfs' is changed 19 | # to the same value as kolla's gid. Apply this workaround for all DPDK nodes, 20 | # along with reboot, so that OvS threads are restarted with this id. 21 | # NOTE: This will not be included in this roles's main.yml, as main.yml should 22 | # be executed after node reboot. 23 | - name: Update gid for hugetlbfs to kolla's gid 24 | group: 25 | name: hugetlbfs 26 | gid: 42477 27 | -------------------------------------------------------------------------------- /playbooks/templates/dev-install_net_config_dpdk.yaml.j2: -------------------------------------------------------------------------------- 1 | #vi:syntax=yaml 2 | --- 3 | network_config: 4 | - type: interface 5 | name: {{ network_info.public_ipv4.interface }} 6 | use_dhcp: true 7 | mtu: {{ public_mtu }} 8 | {% if network_config is defined %} 9 | {{ network_config | to_nice_yaml }} 10 | {% else %} 11 | - type: interface 12 | name: dummy0 13 | use_dhcp: false 14 | nm_controlled: true 15 | - type: ovs_user_bridge 16 | name: br-hostonly 17 | use_dhcp: false 18 | ovs_extra: 19 | - br-set-external-id br-hostonly bridge-id br-hostonly 20 | addresses: 21 | - ip_netmask: {{ hostonly_gateway }}/32 22 | - ip_netmask: {{ hostonly_v6_gateway }}/64 23 | routes: 24 | - destination: {{ hostonly_cidr }} 25 | nexthop: {{ hostonly_gateway }} 26 | members: 27 | - type: ovs_dpdk_port 28 | name: dpdk 29 | rx_queue: 2 30 | members: 31 | - type: interface 32 | name: {{ dpdk_interface }} 33 | mtu: 9000 34 | {% if sriov_interface is defined %} 35 | - type: sriov_pf 36 | name: {{ sriov_interface }} 37 | use_dhcp: false 38 | numvfs: {{ sriov_nic_numvfs | mandatory }} 39 | defroute: false 40 | nm_controlled: true 41 | hotplug: true 42 | promisc: false 43 | addresses: 44 | - ip_netmask: {{ hostonly_sriov_gateway }}/{{ hostonly_sriov_prefix }} 45 | {% endif %} 46 | {% endif %} 47 | -------------------------------------------------------------------------------- /playbooks/roles/tuned/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | galaxy_info: 19 | namespace: openstack 20 | author: OpenStack 21 | description: TripleO OpenStack Role -- tuned 22 | company: Red Hat 23 | license: Apache-2.0 24 | min_ansible_version: 2.7 25 | # 26 | # Provide a list of supported platforms, and for each platform a list of versions. 27 | # If you don't wish to enumerate all versions for a particular platform, use 'all'. 28 | # To view available platforms and versions (or releases), visit: 29 | # https://galaxy.ansible.com/api/v1/platforms/ 30 | # 31 | platforms: 32 | - name: CentOS 33 | versions: 34 | - 7 35 | - 8 36 | 37 | galaxy_tags: 38 | - tripleo 39 | - tuned 40 | 41 | 42 | # List your role dependencies here, one per line. Be sure to remove the '[]' above, 43 | # if you add dependencies to this list. 44 | dependencies: [] 45 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_ovs_dpdk/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | galaxy_info: 19 | namespace: openstack 20 | author: OpenStack 21 | description: TripleO OpenStack Role -- tripleo_ovs_dpdk 22 | company: Red Hat 23 | license: Apache-2.0 24 | min_ansible_version: 2.7 25 | # 26 | # Provide a list of supported platforms, and for each platform a list of versions. 27 | # If you don't wish to enumerate all versions for a particular platform, use 'all'. 28 | # To view available platforms and versions (or releases), visit: 29 | # https://galaxy.ansible.com/api/v1/platforms/ 30 | # 31 | platforms: 32 | - name: CentOS 33 | versions: 34 | - 7 35 | - 8 36 | 37 | galaxy_tags: 38 | - tripleo 39 | 40 | 41 | # List your role dependencies here, one per line. Be sure to remove the '[]' above, 42 | # if you add dependencies to this list. 43 | dependencies: [] 44 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_module_load/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | galaxy_info: 19 | namespace: openstack 20 | author: OpenStack 21 | description: TripleO OpenStack Role -- tripleo_module_load 22 | company: Red Hat 23 | license: Apache-2.0 24 | min_ansible_version: 2.7 25 | # 26 | # Provide a list of supported platforms, and for each platform a list of versions. 27 | # If you don't wish to enumerate all versions for a particular platform, use 'all'. 28 | # To view available platforms and versions (or releases), visit: 29 | # https://galaxy.ansible.com/api/v1/platforms/ 30 | # 31 | platforms: 32 | - name: CentOS 33 | versions: 34 | - 7 35 | - 8 36 | 37 | galaxy_tags: 38 | - tripleo 39 | 40 | 41 | # List your role dependencies here, one per line. Be sure to remove the '[]' above, 42 | # if you add dependencies to this list. 43 | dependencies: [] 44 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_ovs_dpdk/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | # All variables intended for modification should place placed in this file. 19 | 20 | # All variables within this role should have a prefix of "tripleo_ovs_dpdk" 21 | tripleo_ovs_dpdk_debug: "{{ (ansible_verbosity | int) >= 2 | bool }}" 22 | tripleo_ovs_dpdk_pmd_core_list: "" 23 | tripleo_ovs_dpdk_lcore_list: "" 24 | tripleo_ovs_dpdk_memory_channels: 4 25 | tripleo_ovs_dpdk_extra: "" 26 | tripleo_ovs_dpdk_socket_memory: "" 27 | tripleo_ovs_dpdk_revalidator_cores: "" 28 | tripleo_ovs_dpdk_handler_cores: "" 29 | tripleo_ovs_dpdk_emc_insertion_probablity: "" 30 | tripleo_ovs_dpdk_enable_tso: false 31 | tripleo_ovs_dpdk_pmd_auto_lb: false 32 | tripleo_ovs_dpdk_pmd_load_threshold: "" 33 | tripleo_ovs_dpdk_pmd_improvement_threshold: "" 34 | tripleo_ovs_dpdk_pmd_rebal_interval: "" 35 | tripleo_ovs_dpdk_vhost_postcopy_support: false 36 | tripleo_ovs_dpdk_vhost_postcopy_ovs_options: "--mlockall=no" 37 | -------------------------------------------------------------------------------- /playbooks/files/export-dcn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to execute on the central site to generate useful 4 | # data to deploy edge sites. 5 | # Largely inspired by https://docs.openstack.org/project-deploy-guide/tripleo-docs/latest/deployment/standalone.html#extract-deployment-information-from-the-controller-node 6 | 7 | unset OS_CLOUD 8 | export OS_AUTH_TYPE=none 9 | export OS_ENDPOINT=http://127.0.0.1:8006/v1/admin 10 | DIR=/home/stack/exported-data 11 | 12 | mkdir -p $DIR 13 | openstack stack output show standalone EndpointMap --format json \ 14 | | jq '{"parameter_defaults": {"EndpointMapOverride": .output_value}}' \ 15 | > $DIR/endpoint-map.json 16 | 17 | openstack stack output show standalone HostsEntry --format json \ 18 | | jq -r '{"parameter_defaults":{"ExtraHostFileEntries": .output_value}}' \ 19 | > $DIR/extra-host-file-entries.json 20 | 21 | cat < $DIR/oslo.yaml 22 | parameter_defaults: 23 | StandaloneExtraConfig: 24 | oslo_messaging_notify_use_ssl: false 25 | oslo_messaging_rpc_use_ssl: false 26 | EOF 27 | sudo egrep "oslo.*password" /etc/puppet/hieradata/service_configs.json \ 28 | | sed -e s/\"//g -e s/,//g >> $DIR/oslo.yaml 29 | 30 | STANDALONE_LATEST=$(find $HOME/standalone-ansible-*/group_vars -type d -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1) 31 | python3 -c "import json; t = {'parameter_defaults': {'AllNodesExtraMapData': json.loads(open('$STANDALONE_LATEST/overcloud.json').read()) }}; print(t)" > $DIR/all-nodes-extra-map-data.json 32 | 33 | cp $HOME/tripleo-standalone-passwords.yaml $DIR/passwords.yaml 34 | sudo chmod 755 $DIR/passwords.yaml 35 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_module_load/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | # All variables intended for modification should be placed in this file. 19 | 20 | # Load specific kernel modules using a list of hashes. This variable also 21 | # takes the keyword "params" and "state". Params is assumed to be `null` and 22 | # state is assumed to be "present"; tate can be either "present" or "absent". 23 | # 24 | # modules: 25 | # - name: foo 26 | # params: 'bar baz' 27 | # - name: starwars 28 | # - name: starwars 29 | # state: absent 30 | # 31 | # NOTE(cloudnull): This role used to use a non-namespaced option, which has a high 32 | # probability of creating conflicts with other roles in the greater 33 | # ansible ecosystem. To ensure that we're able to retain existing 34 | # variable functionality the "modules" option will supersede 35 | # "tripleo_modules" if defined. This default should be removed 36 | # just as soon as we're validate that the non-namespaced option 37 | # is no longer in use. 38 | tripleo_modules: "{{ modules | default([]) }}" 39 | -------------------------------------------------------------------------------- /playbooks/roles/operators/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install tripleo-operator in current user environment 3 | # and provide plugins and roles to local ansible env. 4 | - name: Ensure there are credentials for accessing registry 5 | tags: 6 | - always 7 | - lab 8 | ansible.builtin.assert: 9 | that: 10 | - registers is defined 11 | - (registers|length) > 0 12 | - registers.0.name is defined 13 | - registers.0.username is defined 14 | - registers.0.password is defined 15 | msg: "It is expected to have defined at least one registry" 16 | 17 | - name: Ensure we have ~/.ansible 18 | tags: 19 | - always 20 | - lab 21 | ansible.builtin.file: 22 | mode: '755' 23 | path: ~/.ansible 24 | state: directory 25 | 26 | - name: Clone tripleo-operator-ansible 27 | register: git_operator 28 | tags: 29 | - always 30 | - lab 31 | ansible.builtin.git: 32 | dest: ~/.ansible/tripleo-operator-ansible 33 | repo: https://opendev.org/openstack/tripleo-operator-ansible 34 | update: "{{ update_operator | bool }}" 35 | # Upstream repo has been retired, this is the latest commit 36 | version: e1abb34ef8eddaebaee63012730b5c65ca731c24 37 | 38 | - name: Build operator collection # noqa no-handler no-changed-when 39 | tags: always 40 | when: git_operator is changed 41 | ansible.builtin.command: "ansible-galaxy collection build --force --output-path /tmp/collections" 42 | register: collection_name 43 | args: 44 | chdir: ~/.ansible/tripleo-operator-ansible 45 | 46 | - name: Install operator collection # noqa no-handler no-changed-when 47 | tags: always 48 | when: git_operator is changed 49 | ansible.builtin.command: "ansible-galaxy collection install --force {{ collection_name.stdout.split(' ')[-1] }}" 50 | args: 51 | chdir: ~/.ansible/tripleo-operator-ansible 52 | -------------------------------------------------------------------------------- /playbooks/roles/tuned/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | # "{{ role_name }}" will search for and load any operating system variable file 19 | # found within the "vars/" path. If no OS files are found the task will skip. 20 | - name: Gather variables for each operating system 21 | ansible.builtin.include_vars: "{{ item }}" 22 | with_first_found: 23 | - skip: true 24 | files: 25 | - "{{ ansible_facts['distribution'] | lower }}-{{ ansible_facts['distribution_version'] | lower }}.yml" 26 | - "{{ ansible_facts['distribution'] | lower }}-{{ ansible_facts['distribution_major_version'] | lower }}.yml" 27 | - "{{ ansible_facts['os_family'] | lower }}-{{ ansible_facts['distribution_major_version'] | lower }}.yml" 28 | - "{{ ansible_facts['distribution'] | lower }}.yml" 29 | - "{{ ansible_facts['os_family'] | lower }}-{{ ansible_facts['distribution_version'].split('.')[0] }}.yml" 30 | - "{{ ansible_facts['os_family'] | lower }}.yml" 31 | tags: 32 | - always 33 | 34 | - ansible.builtin.include_tasks: tuned_install.yml 35 | when: 36 | - (tuned_system_packages | length) > 0 37 | 38 | - name: Check for tuned-adm 39 | ansible.builtin.command: >- 40 | which tuned-adm 41 | environment: 42 | PATH: "/bin:/usr/bin:/sbin:/usr/sbin" 43 | changed_when: false 44 | failed_when: false 45 | register: tuned_check 46 | 47 | - ansible.builtin.include_tasks: tuned_config.yml 48 | when: 49 | - not ansible_check_mode 50 | - tuned_check.rc == 0 51 | -------------------------------------------------------------------------------- /playbooks/templates/dev-install_net_config.yaml.j2: -------------------------------------------------------------------------------- 1 | #vi:syntax=yaml 2 | --- 3 | network_config: 4 | - type: ovs_bridge 5 | name: br-ex 6 | use_dhcp: true 7 | mtu: {{ public_mtu }} 8 | ovs_extra: 9 | - br-set-external-id br-ex bridge-id br-ex 10 | members: 11 | - type: interface 12 | name: {{ network_info.public_ipv4.interface }} 13 | primary: true 14 | mtu: {{ public_mtu }} 15 | {% if public_default_route %} 16 | routes: 17 | - default: true 18 | next_hop: {{ network_info.public_ipv4.gateway }} 19 | {% endif %} 20 | {% if network_config is defined %} 21 | {{ network_config | to_nice_yaml }} 22 | {% else %} 23 | - type: ovs_bridge 24 | name: br-ctlplane 25 | use_dhcp: false 26 | ovs_extra: 27 | - br-set-external-id br-ctlplane bridge-id br-ctlplane 28 | addresses: 29 | - ip_netmask: {{ local_ip }}/{{ control_plane_prefix }} 30 | members: 31 | - type: interface 32 | name: dummy0 33 | nm_controlled: true 34 | mtu: {{ dcn_az is defined | ternary(ctlplane_mtu, public_mtu) }} 35 | {% for ip in tunnel_remote_ips %} 36 | - type: ovs_tunnel 37 | name: "tun-ctlplane-{{ ip | to_uuid }}" 38 | tunnel_type: vxlan 39 | ovs_options: 40 | - remote_ip={{ ip }} 41 | - key=100 42 | {% endfor %} 43 | - type: ovs_bridge 44 | name: br-hostonly 45 | use_dhcp: false 46 | ovs_extra: 47 | - br-set-external-id br-hostonly bridge-id br-hostonly 48 | addresses: 49 | - ip_netmask: {{ hostonly_gateway }}/32 50 | - ip_netmask: {{ hostonly_v6_gateway }}/64 51 | routes: 52 | - destination: {{ hostonly_cidr }} 53 | nexthop: {{ hostonly_gateway }} 54 | members: 55 | {% for ip in tunnel_remote_ips %} 56 | - type: ovs_tunnel 57 | name: "tun-hostonly-{{ ip | to_uuid }}" 58 | tunnel_type: vxlan 59 | ovs_options: 60 | - remote_ip={{ ip }} 61 | - key=101 62 | {% endfor %} 63 | - type: interface 64 | name: dummy1 65 | nm_controlled: true 66 | mtu: {{ dcn_az is defined | ternary(hostonly_mtu, public_mtu) }} 67 | {% if sriov_interface is defined %} 68 | - type: sriov_pf 69 | name: {{ sriov_interface }} 70 | numvfs: {{ sriov_nic_numvfs | mandatory }} 71 | mtu: 9000 72 | use_dhcp: false 73 | defroute: false 74 | nm_controlled: true 75 | hotplug: true 76 | promisc: false 77 | addresses: 78 | - ip_netmask: {{ hostonly_sriov_gateway }}/{{ hostonly_sriov_prefix }} 79 | {% endif %} 80 | {% endif %} 81 | -------------------------------------------------------------------------------- /playbooks/roles/tuned/tasks/tuned_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | - name: Ensure profile directory exists 19 | ansible.builtin.file: 20 | path: "/etc/tuned/{{ tuned_profile }}" 21 | state: directory 22 | owner: root 23 | group: root 24 | mode: 0755 25 | when: 26 | - (tuned_custom_profile is defined) and ((tuned_custom_profile | length) > 0) 27 | 28 | - name: Create custom tuned profile 29 | ansible.builtin.copy: 30 | content: "{{ tuned_custom_profile }}" 31 | dest: "/etc/tuned/{{ tuned_profile }}/tuned.conf" 32 | owner: root 33 | group: root 34 | mode: 0644 35 | when: 36 | - (tuned_custom_profile is defined) and ((tuned_custom_profile | length) > 0) 37 | 38 | - name: Check tuned active profile 39 | ansible.builtin.slurp: 40 | src: "/etc/tuned/active_profile" 41 | register: tuned_active_profile 42 | 43 | - name: Check Tuned Configuration file exists 44 | ansible.builtin.stat: 45 | path: "/etc/tuned/{{ tuned_profile }}-variables.conf" 46 | register: tuned_conf_stat_result 47 | 48 | - name: Fail if tuned profile conf is absent but isolated cores is provided 49 | ansible.builtin.fail: 50 | msg: "Tuned profile conf file is not available to configure isolated cores" 51 | when: 52 | - tuned_isolated_cores is defined 53 | - (tuned_isolated_cores | length) > 0 54 | - not (tuned_conf_stat_result.stat.exists | bool) 55 | 56 | - name: "Configure isolated cores for profile {{ tuned_profile }}" 57 | ansible.builtin.lineinfile: 58 | dest: "/etc/tuned/{{ tuned_profile }}-variables.conf" 59 | regexp: '^isolated_cores=.*' 60 | line: 'isolated_cores={{ tuned_isolated_cores }}' 61 | when: 62 | - tuned_isolated_cores is defined 63 | - (tuned_isolated_cores | length) > 0 64 | - (tuned_conf_stat_result.stat.exists | bool) 65 | 66 | - name: Enable tuned profile 67 | ansible.builtin.command: >- 68 | tuned-adm profile {{ tuned_profile }} 69 | environment: 70 | PATH: "/bin:/usr/bin:/sbin:/usr/sbin" 71 | when: 72 | - ((tuned_active_profile['content'] | b64decode).strip()) != tuned_profile 73 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_module_load/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | 18 | # "tripleo_module_load" will search for and load any operating system variable file 19 | 20 | - name: Kernel module block 21 | become: true 22 | block: 23 | - name: Ensure /etc/modules-load.d exists 24 | ansible.builtin.file: 25 | path: /etc/modules-load.d 26 | state: directory 27 | setype: etc_t 28 | selevel: s0 29 | 30 | - name: "Load modules" 31 | community.general.modprobe: 32 | name: "{{ item.name }}" 33 | params: "{{ item.params | default(omit) }}" 34 | state: "{{ item.state | default('present') }}" 35 | loop: "{{ tripleo_modules }}" 36 | loop_control: 37 | label: "{{ item.name }}" 38 | 39 | - name: "Persist modules via modules-load.d" 40 | ansible.builtin.template: 41 | dest: "/etc/modules-load.d/{{ item.name }}.conf" 42 | src: module-load.conf.j2 43 | loop: "{{ tripleo_modules }}" 44 | loop_control: 45 | label: "{{ item.name }}" 46 | register: _tripleo_modules_add 47 | when: 48 | - (item.state | default('present')) == 'present' 49 | 50 | - name: "Drop module persistence" 51 | ansible.builtin.file: 52 | path: "/etc/modules-load.d/{{ item.name }}.conf" 53 | state: absent 54 | loop: "{{ tripleo_modules }}" 55 | loop_control: 56 | label: "{{ item.name }}" 57 | register: _tripleo_modules_remove 58 | when: 59 | - (item.state | default('present')) == 'absent' 60 | 61 | - name: "Set modules persistence via /etc/modules" 62 | ansible.builtin.lineinfile: 63 | dest: /etc/modules 64 | line: "{{ item.name }} {{ item.params | default('') }}" 65 | state: "{{ item.state | default('present') }}" 66 | create: true 67 | loop: "{{ tripleo_modules }}" 68 | loop_control: 69 | label: "{{ item.name }}" 70 | 71 | - name: Modules reload 72 | ansible.builtin.systemd: 73 | name: systemd-modules-load.service 74 | state: restarted 75 | when: 76 | - _tripleo_modules_add.changed or _tripleo_modules_remove.changed 77 | -------------------------------------------------------------------------------- /playbooks/roles/ceph/tasks/storage-network.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create network_data file 3 | ansible.builtin.copy: 4 | dest: "{{ network_data }}" 5 | mode: '644' 6 | content: | 7 | - name: Storage 8 | mtu: 1350 9 | vip: true 10 | name_lower: storage 11 | dns_domain: storage.mydomain.tld. 12 | service_net_map_replace: storage 13 | subnets: 14 | storage_subnet: 15 | ip_subnet: '{{ ceph_network }}' 16 | allocation_pools: [{'start': '{{ start }}', 'end': '{{ end }}'}] 17 | 18 | - name: Create deployed_network environment file (with VIPs) 19 | ansible.builtin.copy: 20 | dest: "{{ deployed_network }}" 21 | mode: '644' 22 | content: | 23 | resource_registry: 24 | OS::TripleO::Network::Ports::ControlPlaneVipPort: /usr/share/openstack-tripleo-heat-templates/network/ports/deployed_vip_ctlplane.yaml 25 | OS::TripleO::Network::Ports::StorageVipPort: network/ports/deployed_vip_storage.yaml 26 | OS::TripleO::Network: /usr/share/openstack-tripleo-heat-templates/network/deployed_networks.yaml 27 | parameter_defaults: 28 | NodePortMap: 29 | standalone: 30 | ctlplane: 31 | ip_address: {{ local_ip }} 32 | ip_subnet: {{ local_ip }}/{{ control_plane_prefix }} 33 | ip_address_uri: {{ local_ip }} 34 | storage: 35 | ip_address: {{ mon_ip }} 36 | ip_subnet: {{ dummy_ip_cidr }} 37 | ip_address_uri: {{ mon_ip }} 38 | ControlPlaneVipData: 39 | fixed_ips: 40 | - ip_address: {{ control_plane_ip }} 41 | name: control_virtual_ip 42 | network: 43 | tags: 44 | - "{{ control_plane_cidr }}" 45 | subnets: 46 | - ip_version: 4 47 | VipPortMap: 48 | storage: 49 | ip_address: {{ dummy_vip }} 50 | ip_address_uri: {{ dummy_vip }} 51 | ip_subnet: {{ dummy_vip ~ '/' ~ control_plane_prefix | string }} 52 | DeployedNetworkEnvironment: 53 | net_attributes_map: 54 | storage: 55 | network: 56 | dns_domain: storage.mydomain.tld. 57 | mtu: 1350 58 | name: storage 59 | tags: 60 | - tripleo_network_name=Storage 61 | - tripleo_net_idx=0 62 | - tripleo_service_net_map_replace=storage 63 | - tripleo_vip=true 64 | subnets: 65 | storage_subnet: 66 | cidr: {{ ceph_network }} 67 | dns_nameservers: [] 68 | gateway_ip: null 69 | host_routes: [] 70 | ip_version: 4 71 | name: storage_subnet 72 | net_cidr_map: 73 | storage: 74 | - {{ ceph_network }} 75 | net_ip_version_map: 76 | storage: 4 77 | -------------------------------------------------------------------------------- /playbooks/roles/network_info/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Read network info if present 3 | ansible.builtin.slurp: 4 | src: &networkinfo /home/stack/dev-install-network-info.yaml 5 | register: networkinfo_file 6 | ignore_errors: true 7 | 8 | - name: Set network_info from file 9 | ansible.builtin.set_fact: 10 | network_info: "{{ networkinfo_file['content'] | b64decode | from_json }}" 11 | when: not networkinfo_file.failed 12 | 13 | - name: Store network info before we change it 14 | when: networkinfo_file.failed 15 | block: 16 | - name: Gather host network info 17 | ansible.builtin.setup: 18 | gather_subset: "network" 19 | 20 | - name: Set ip with netmask facts 21 | ansible.builtin.set_fact: 22 | public_ipv4_full: "{{ ansible_facts.default_ipv4.address + '/' + ansible_facts.default_ipv4.netmask }}" 23 | 24 | - name: Set network_info from gathered facts 25 | ansible.builtin.set_fact: 26 | network_info: 27 | dns: "{{ ansible_facts.dns.nameservers }}" 28 | public_ipv4: "{{ ansible_facts.default_ipv4 }}" 29 | public_ipv6: "{{ ansible_facts.default_ipv6 }}" 30 | public_ipv4_cidr: "{{ public_ipv4_full | ansible.utils.ipaddr('prefix') }}" 31 | 32 | - name: Write network_info to file 33 | ansible.builtin.copy: 34 | dest: *networkinfo 35 | content: "{{ network_info | to_nice_json }}" 36 | mode: '755' 37 | 38 | - name: Find network devices with a device link 39 | ansible.builtin.find: 40 | paths: /sys/class/net 41 | patterns: 42 | - device 43 | file_type: link 44 | follow: true 45 | depth: 2 46 | recurse: true 47 | use_regex: false 48 | register: device_links 49 | 50 | - name: Extract paths from device_links 51 | ansible.builtin.set_fact: 52 | device_links: "{{ device_links.files | map(attribute='path') | list }}" 53 | 54 | - name: Extract device names from device_links 55 | ansible.builtin.set_fact: 56 | physical_nics: "{{ physical_nics + [item | dirname | basename] }}" 57 | loop: "{{ device_links }}" 58 | vars: 59 | physical_nics: [] 60 | 61 | - name: Initialise SR-IOV PFs to an empty list 62 | ansible.builtin.set_fact: 63 | sriov_pfs: [] 64 | 65 | - name: Find SR-IOV PFs 66 | ansible.builtin.find: 67 | paths: "{{ device_links }}" 68 | patterns: 69 | - sriov_totalvfs 70 | register: sriov_totalvfs 71 | 72 | - name: Extract device names for SR-IOV PFs 73 | ansible.builtin.set_fact: 74 | sriov_pfs: "{{ sriov_pfs + [item | dirname | dirname | basename] }}" 75 | loop: "{{ sriov_totalvfs.files | map(attribute='path') | list }}" 76 | 77 | - name: Initialise SR-IOV VFs to an empty list 78 | ansible.builtin.set_fact: 79 | sriov_vfs: [] 80 | 81 | - name: Find SR-IOV VFs 82 | ansible.builtin.find: 83 | paths: "{{ device_links }}" 84 | patterns: 85 | - physfn 86 | file_type: link 87 | register: sriov_physfndir 88 | 89 | - name: Extract device names for SR-IOV VFs 90 | ansible.builtin.set_fact: 91 | sriov_vfs: "{{ sriov_vfs + [item | dirname | dirname | basename] }}" 92 | loop: "{{ sriov_physfndir.files | map(attribute='path') | list }}" 93 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # The installation target used when initializing the local ansible inventory. 2 | # N.B. This is *only* used when initializing the local ansible inventory file. 3 | # Specifically it is not used if the inventory file already exists. 4 | # 5 | # It is recommended to run: 6 | # make config host= 7 | # 8 | SHELL=/bin/bash 9 | 10 | host ?= my_osp_host 11 | user ?= stack 12 | ansible_args ?= 13 | overrides ?= local-overrides.yaml 14 | 15 | ANSIBLE_CMD=ANSIBLE_FORCE_COLOR=true ansible-playbook $(ansible_args) -i inventory.yaml -e @$(overrides) 16 | 17 | usage: 18 | @echo 'Usage:' 19 | @echo 20 | @echo 'make config host=' 21 | @echo 'make osp_full' 22 | @echo 23 | @echo 'Individual install phase targets:' 24 | @echo ' local_requirements: Install Ansible requirements required to run dev-install' 25 | @echo ' prepare_host: Host configuration required before installing standalone, including rhos-release' 26 | @echo ' network: Host networking configuration required before installing standalone' 27 | @echo ' install_stack: Install TripleO standalone' 28 | @echo ' prepare_stack: Configure defaults in OSP and create shiftstack user' 29 | @echo 30 | @echo 'Utility targets:' 31 | @echo ' local_os_client: Configure local clouds.yaml to use standalone cloud' 32 | @echo ' prepare_stack_testconfig: Download cirros image and create a test network, router and security group' 33 | @echo ' post_install: Run any shell defined in `post_install`' 34 | 35 | # 36 | # Targets which initialize local state 37 | # 38 | 39 | .PHONY: config 40 | config: inventory.yaml $(overrides) 41 | 42 | inventory.yaml: 43 | echo -e "all:\n hosts:\n standalone:\n ansible_host: $(host)\n ansible_user: $(user)\n" > $@ 44 | 45 | $(overrides): 46 | echo -e "# Override default variables by putting them in this file\nstandalone_host: $(host)" > $(overrides) 47 | 48 | 49 | # 50 | # Deploy targets 51 | # 52 | 53 | .PHONY: osp_full 54 | osp_full: local_requirements prepare_host network install_stack prepare_stack local_os_client 55 | 56 | .PHONY: local_requirements 57 | local_requirements: inventory.yaml $(overrides) 58 | $(ANSIBLE_CMD) playbooks/local_requirements.yaml 59 | 60 | .PHONY: prepare_host 61 | prepare_host: inventory.yaml $(overrides) 62 | $(ANSIBLE_CMD) playbooks/prepare_host.yaml 63 | 64 | .PHONY: network 65 | network: inventory.yaml $(overrides) 66 | $(ANSIBLE_CMD) playbooks/network.yaml 67 | 68 | .PHONY: install_stack 69 | install_stack: inventory.yaml $(overrides) 70 | $(ANSIBLE_CMD) playbooks/install_stack.yaml 71 | 72 | .PHONY: prepare_stack 73 | prepare_stack: inventory.yaml $(overrides) 74 | $(ANSIBLE_CMD) playbooks/prepare_stack.yaml 75 | 76 | .PHONY: prepare_stack_testconfig 77 | prepare_stack_testconfig: inventory.yaml $(overrides) 78 | $(ANSIBLE_CMD) playbooks/prepare_stack_testconfig.yaml 79 | 80 | .PHONY: post_install 81 | post_install: inventory.yaml $(overrides) 82 | $(ANSIBLE_CMD) playbooks/post_install.yaml 83 | 84 | .PHONY: local_os_client 85 | local_os_client: inventory.yaml $(overrides) 86 | $(ANSIBLE_CMD) playbooks/local_os_client.yaml 87 | 88 | .PHONY: certs 89 | certs: $(overrides) 90 | $(ANSIBLE_CMD) playbooks/certs.yaml 91 | 92 | .PHONY: destroy 93 | destroy: inventory.yaml $(overrides) 94 | $(ANSIBLE_CMD) playbooks/destroy.yaml 95 | -------------------------------------------------------------------------------- /playbooks/roles/simpleca/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # With thanks to https://milliams.com/posts/2020/ansible-certificate-authority/ 3 | 4 | - name: Install crypto library for openssl_* modules # noqa ignore-errors 5 | become: true 6 | become_user: root 7 | # To not fail on non-RPM systems let's just ignore errors. 8 | ignore_errors: true 9 | ansible.builtin.yum: 10 | state: installed 11 | name: python3-cryptography 12 | 13 | - name: Create the CA directory 14 | ansible.builtin.file: 15 | path: "{{ ca_dir }}" 16 | state: directory 17 | mode: '750' 18 | 19 | - name: Run the tasks to create CA cert and key when not provided 20 | when: ssl_ca_cert is not defined or ssl_ca_key is not defined 21 | block: 22 | - name: Create CA key 23 | community.crypto.openssl_privatekey: 24 | path: "{{ ca_dir }}/simpleca.key" 25 | register: ca_key 26 | 27 | - name: Create the CA CSR 28 | community.crypto.openssl_csr: 29 | path: "{{ ca_dir }}/simpleca.csr" 30 | privatekey_path: "{{ ca_key.filename }}" 31 | common_name: "simpleca" 32 | basic_constraints: 33 | - "CA:TRUE" 34 | register: ca_csr 35 | 36 | - name: Sign the CA CSR 37 | community.crypto.x509_certificate: 38 | path: "{{ ca_dir }}/simpleca.crt" 39 | csr_path: "{{ ca_csr.filename }}" 40 | privatekey_path: "{{ ca_key.filename }}" 41 | provider: selfsigned 42 | register: ca_crt 43 | 44 | - name: Create facts for CA files 45 | ansible.builtin.set_fact: 46 | ca_crt_path: "{{ ca_crt.filename }}" 47 | ca_key_path: "{{ ca_key.filename }}" 48 | 49 | - name: Run the tasks to create temp files for CA cert and key when provided 50 | when: ssl_ca_cert is defined or ssl_ca_key is defined 51 | block: 52 | - name: "Write the CA cert into {{ ca_dir }}" 53 | ansible.builtin.copy: 54 | content: "{{ ssl_ca_cert | mandatory }}" 55 | dest: "{{ ca_dir }}/simpleca.crt" 56 | mode: '400' 57 | 58 | - name: "Write the CA key into {{ ca_dir }}" 59 | ansible.builtin.copy: 60 | content: "{{ ssl_ca_key | mandatory }}" 61 | dest: "{{ ca_dir }}/simpleca.key" 62 | mode: '400' 63 | 64 | - name: Create facts for CA files 65 | ansible.builtin.set_fact: 66 | ca_crt_path: "{{ ca_dir }}/simpleca.crt" 67 | ca_key_path: "{{ ca_dir }}/simpleca.key" 68 | 69 | - name: Create a private key for {{ cert_user }} 70 | community.crypto.openssl_privatekey: 71 | path: "{{ cert_dir }}/{{ cert_user }}.key" 72 | register: user_key 73 | 74 | - name: Create a CSR for {{ cert_user }} 75 | community.crypto.openssl_csr: 76 | path: "{{ cert_dir }}/{{ cert_user }}.csr" 77 | privatekey_path: "{{ user_key.filename }}" 78 | common_name: "{{ cert_name }}" 79 | subject_alt_name: 80 | - "DNS:{{ cert_name }}" 81 | - "DNS:{{ standalone_host }}" 82 | - "IP:{{ public_api }}" 83 | - "IP:{{ control_plane_ip }}" 84 | - "IP:{{ hostonly_gateway }}" 85 | - "IP:{{ hostonly_v6_gateway }}" 86 | register: user_csr 87 | 88 | - name: Sign the CSR for {{ cert_user }} 89 | community.crypto.x509_certificate: 90 | path: "{{ cert_dir }}/{{ cert_user }}.crt" 91 | csr_path: "{{ user_csr.filename }}" 92 | provider: ownca 93 | ownca_path: "{{ ca_crt_path }}" 94 | ownca_privatekey_path: "{{ ca_key_path }}" 95 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_kernel/tasks/reboot.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | # Check if os-net-config has run once, if yes, no need for the below workaround 18 | - name: Find the ifcfg file generated by os-net-config 19 | find: 20 | paths: /etc/sysconfig/network-scripts/ 21 | patterns: ifcfg-* 22 | contains: "# This file is autogenerated by os-net-config" 23 | register: os_net_ifcfg_files 24 | 25 | # Provisioning Network workaround 26 | # The script will be executed before os-net-config, in which case, only Provisioning network will have IP 27 | # BOOTPROTO of all interface config files (except provisioning), will be set to "none" to avoid reboot failing to acquire IP on other networks 28 | - name: Apply workaround for node reboot 29 | block: 30 | - name: Find the ifcfg files 31 | find: 32 | paths: /etc/sysconfig/network-scripts/ 33 | patterns: ifcfg-* 34 | register: ifcfg_files 35 | # NOTE(mwhahaha): On computes collecting all the network facts is a huge 36 | # performance issue. So let's only get the ansible facts for the ifcfg 37 | # files which will avoid all the tap interfaces. This takes a while but 38 | # results in less memory utilization for the rest of the deployment. 39 | - name: Get ifcfg facts 40 | ansible.builtin.setup: 41 | gather_subset: 42 | - '!all' 43 | - '!min' 44 | - network 45 | filter: "{{ 'ansible_' + item.path | regex_replace('(^.*ifcfg-)(.*)', '\\2') | replace('-', '_') }}" 46 | loop: "{{ ifcfg_files.files | flatten(levels=1) }}" 47 | loop_control: 48 | label: "{{ item.path | regex_replace('(^.*ifcfg-)(.*)', '\\2') | replace('-', '_') }}" 49 | - name: Replace BOOTPROTO to none for interfaces which does not have IP 50 | replace: 51 | dest: "{{ item.path }}" 52 | regexp: '^BOOTPROTO=.*' 53 | replace: 'BOOTPROTO=none' 54 | when: 55 | - item.path | regex_replace('(^.*ifcfg-)(.*)', '\\2') != "lo" 56 | # Ensure the interface information is available in the facts 57 | - hostvars[inventory_hostname]['ansible_facts'][item.path | regex_replace('(^.*ifcfg-)(.*)', '\\2') | replace('-', '_')] is defined 58 | # This condition will list all the interfaces except the one with valid IP (which is Provisioning network at this stage) 59 | # Simpler Version - hostvars[inventory_hostname]['ansible_' + iface_name ]['ipv4'] is undefined 60 | - hostvars[inventory_hostname]['ansible_facts'][item.path | regex_replace('(^.*ifcfg-)(.*)', '\\2') | replace('-', '_')]['ipv4'] is undefined 61 | with_items: 62 | - "{{ ifcfg_files.files }}" 63 | become: true 64 | when: 65 | - os_net_ifcfg_files.matched is defined 66 | - os_net_ifcfg_files.matched == 0 67 | 68 | - name: Reboot debug message 69 | debug: 70 | msg: "Going to reboot the node after applying kernel args..." 71 | 72 | # Reboot the node 73 | - name: Reboot after kernel args update 74 | reboot: 75 | post_reboot_delay: "{{ tripleo_kernel_post_reboot_delay }}" 76 | reboot_timeout: "{{ tripleo_kernel_reboot_timeout }}" 77 | -------------------------------------------------------------------------------- /playbooks/prepare_stack_testconfig.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: stack 5 | gather_facts: false 6 | vars_files: vars/defaults.yaml 7 | name: Create testconfig resources 8 | tasks: 9 | - name: Gather host environment variables 10 | ansible.builtin.setup: 11 | filter: ansible_env 12 | 13 | - name: Ensure remote .ssh directory 14 | ansible.builtin.file: 15 | path: "{{ ansible_env.HOME }}/.ssh" 16 | state: directory 17 | owner: stack 18 | group: stack 19 | mode: '700' 20 | 21 | - name: Copy ssh public key to host 22 | ansible.builtin.copy: 23 | src: "{{ testconfig_public_key }}" 24 | dest: "{{ ansible_env.HOME }}/.ssh/{{ testconfig_public_key | basename }}" 25 | owner: stack 26 | group: stack 27 | mode: '600' 28 | register: testconfig_public_key_copy 29 | 30 | - name: Configure resources for openshift user # noqa no-changed-when 31 | ansible.builtin.shell: | 32 | set -e -o pipefail 33 | 34 | if ! openstack keypair show default >/dev/null; then 35 | openstack keypair create --public-key {{ testconfig_public_key_copy.dest }} default 36 | fi 37 | if ! openstack network show private >/dev/null; then 38 | openstack network create --internal private 39 | fi 40 | if ! openstack subnet show private-subnet >/dev/null; then 41 | openstack subnet create private-subnet --subnet-range {{ testconfig_private_cidr }} --network private 42 | fi 43 | # create basic security group to allow ssh/ping/dns 44 | if ! openstack security group show basic >/dev/null; then 45 | openstack security group create basic 46 | fi 47 | if ! openstack security group rule list basic | grep "22:22"; then 48 | openstack security group rule create basic --protocol tcp --dst-port 22:22 --remote-ip 0.0.0.0/0 49 | fi 50 | if ! openstack security group rule list basic | grep "icmp"; then 51 | openstack security group rule create --protocol icmp basic 52 | fi 53 | if ! openstack security group rule list basic | grep "53:53"; then 54 | openstack security group rule create --protocol udp --dst-port 53:53 basic 55 | fi 56 | # Create a router for private<->external 57 | if ! openstack router show private-subnet-external >/dev/null; then 58 | openstack router create private-subnet-external 59 | openstack router set private-subnet-external --external-gateway external 60 | openstack router add subnet private-subnet-external private-subnet 61 | fi 62 | environment: 63 | OS_CLOUD: openshift 64 | 65 | - name: Set images directory 66 | ansible.builtin.set_fact: 67 | images_dir: "{{ ansible_env.HOME }}/images" 68 | 69 | - name: Create images directory 70 | ansible.builtin.file: 71 | path: "{{ images_dir }}" 72 | state: directory 73 | mode: '755' 74 | 75 | - name: Extract Cirros filename 76 | ansible.builtin.set_fact: 77 | cirros_filename: "{{ cirros_url | urlsplit('path') | basename }}" 78 | 79 | - name: Download Cirros image 80 | ansible.builtin.get_url: 81 | url: "{{ cirros_url }}" 82 | dest: "{{ images_dir }}/{{ cirros_filename }}" 83 | mode: '644' 84 | register: cirros 85 | 86 | - name: Import Cirros image # noqa no-changed-when 87 | ansible.builtin.shell: | 88 | if ! openstack image show cirros >/dev/null; then 89 | openstack image create cirros --container-format bare --disk-format qcow2 --public \ 90 | --file "{{ cirros.dest }}" 91 | fi 92 | environment: 93 | OS_CLOUD: standalone 94 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_kernel/tasks/kernelargs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | - name: Get the command line args of the node # noqa no-changed-when 18 | ansible.builtin.command: cat /proc/cmdline 19 | register: cmdline 20 | 21 | - name: TSX KernelArgs compute node reboot prevention 22 | when: 23 | - '"nova_libvirt" in groups' 24 | block: 25 | - name: Check if node has a nova.conf 26 | ansible.builtin.stat: 27 | path: /var/lib/config-data/puppet-generated/nova_libvirt/etc/nova/nova.conf 28 | register: nova_conf_check 29 | 30 | - name: Enabling defer_reboot when TSX was added or appended 31 | when: 32 | - nova_conf_check.stat.exists 33 | - tripleo_kernel_args is regex("^[\s]*tsx=[^\s]+[\s]*$") 34 | block: 35 | - name: Warn operator about workload protection 36 | debug: 37 | msg: | 38 | Automated reboot for this node has been defered because it is already provisionned. 39 | Please schedule a manual reboot after this deployment is completed. 40 | 41 | - name: Setting defer reboot fact 42 | ansible.builtin.set_fact: 43 | tripleo_kernel_defer_reboot: true 44 | tripleo_kernel_reboot_protection: true 45 | 46 | - name: Check if the kernelargs entry is already present in the file 47 | replace: 48 | regexp: TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS 49 | dest: /etc/default/grub 50 | replace: '' 51 | check_mode: true 52 | register: grub_file_entry_check 53 | 54 | # Kernel Args Configuration 55 | - block: 56 | # Leapp does not recognise grun entries starting other than GRUB 57 | # It results wrong formatting of entries in file /etc/default/grub 58 | # In order to fix it for FFU (queens to train), TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS has been renamed 59 | # Ensure the fresh deployment is also alinged with the same name 60 | - name: Delete older name TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS entries if present 61 | ansible.builtin.lineinfile: 62 | dest: /etc/default/grub 63 | regexp: 'TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS' 64 | state: absent 65 | - name: Ensure the kernel args ( {{ tripleo_kernel_args }} ) is present as GRUB_TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS 66 | ansible.builtin.lineinfile: 67 | dest: /etc/default/grub 68 | regexp: '^GRUB_TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS.*' 69 | insertafter: '^GRUB_CMDLINE_LINUX.*' 70 | line: 'GRUB_TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS=" {{ tripleo_kernel_args }} "' 71 | - name: Add GRUB_TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS to the GRUB_CMDLINE_LINUX parameter 72 | ansible.builtin.lineinfile: 73 | dest: /etc/default/grub 74 | line: 'GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX:+$GRUB_CMDLINE_LINUX }${GRUB_TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS}"' 75 | insertafter: '^GRUB_TRIPLEO_HEAT_TEMPLATE_KERNEL_ARGS.*' 76 | - name: Check grub config paths 77 | ansible.builtin.stat: 78 | path: "{{ item }}" 79 | register: grub_stat 80 | loop: 81 | - /boot/efi/EFI/BOOT 82 | - /boot/efi/EFI/redhat 83 | - /boot/efi/EFI/centos 84 | - /boot/efi/EFI/fedora 85 | - name: Generate grub config 86 | ansible.builtin.command: "grub2-mkconfig -o /boot/grub2/grub.cfg" 87 | 88 | - name: Generate EFI grub config 89 | ansible.builtin.command: "grub2-mkconfig -o {{ item.stat.path }}/grub.cfg" 90 | when: item.stat.exists|bool 91 | loop: "{{ grub_stat.results }}" 92 | 93 | - name: Copy grubenv to EFI directory 94 | ansible.builtin.copy: 95 | remote_src: true 96 | src: /boot/grub2/grubenv 97 | dest: "{{ item.stat.path }}/grubenv" 98 | mode: '600' 99 | owner: root 100 | group: root 101 | when: item.stat.exists|bool 102 | loop: "{{ grub_stat.results }}" 103 | - name: Set reboot required fact 104 | ansible.builtin.set_fact: 105 | reboot_required: true 106 | become: true 107 | when: 108 | - cmdline.stdout_lines is defined 109 | - tripleo_kernel_args|string 110 | - tripleo_kernel_args not in cmdline.stdout 111 | 112 | # Apply DPDK workarounds before reboot 113 | - name: Apply DPDK workarounds 114 | ansible.builtin.include_role: 115 | name: tripleo_ovs_dpdk 116 | tasks_from: workarounds.yml 117 | when: reboot_required is defined and reboot_required 118 | 119 | # Kernel modules loading 120 | - name: Load type1 IOMMU driver for VFIO on boot 121 | import_role: 122 | name: tripleo_module_load 123 | vars: 124 | modules: 125 | - name: vfio_iommu_type1 126 | when: tripleo_kernel_args is search("iommu") 127 | 128 | - name: Reboot block 129 | when: 130 | - reboot_required is defined and reboot_required 131 | - not tripleo_kernel_defer_reboot|bool 132 | - not tripleo_kernel_reboot_protection|bool 133 | block: 134 | - name: Reboot tasks 135 | ansible.builtin.include_tasks: reboot.yaml 136 | -------------------------------------------------------------------------------- /playbooks/roles/ceph/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Tasks for ceph-adm 2 | when: ceph_adm_enabled 3 | become: true 4 | become_user: stack 5 | block: 6 | - name: Set facts for ceph-adm 7 | ansible.builtin.set_fact: 8 | stack: standalone 9 | mon_ip: "{{ local_ip }}" 10 | ceph_network: "{{ control_plane_cidr }}" 11 | network_data: "{{ ansible_env.HOME }}/network_data.yaml" 12 | deployed_network: "{{ ansible_env.HOME }}/deployed_network.yaml" 13 | osd_spec: "{{ ansible_env.HOME }}/osd_spec.yaml" 14 | initial_ceph_conf: "{{ ansible_env.HOME }}/initial_ceph.conf" 15 | ceph_spec: "{{ ansible_env.HOME }}/ceph_spec.yaml" 16 | containers_prep: "{{ ansible_env.HOME }}/containers-prepare-parameters.yaml" 17 | deployed_ceph: "{{ ansible_env.HOME }}/deployed_ceph.yaml" 18 | 19 | - name: Configure Storage Network 20 | ansible.builtin.include_tasks: storage-network.yml 21 | vars: 22 | interface: br-ctlplane 23 | dummy_ip_cidr: "{{ mon_ip ~ '/' ~ control_plane_prefix | string }}" 24 | dummy_vip: "{{ control_plane_ip }}" 25 | start: "{{ control_plane_cidr | nthhost(4) }}" 26 | end: "{{ control_plane_cidr | nthhost(250) }}" 27 | 28 | - name: Create OSD spec file 29 | ansible.builtin.copy: 30 | dest: "{{ osd_spec }}" 31 | content: | 32 | data_devices: 33 | paths: 34 | {% if ceph_devices is defined and (ceph_devices | length > 0) and (ceph_devices is not true) and (not ceph_devices_to_lvm | default(false)) %} 35 | {% for d in ceph_devices %} 36 | - {{ d }} 37 | {% endfor %} 38 | {% else %} 39 | - /dev/vg_ceph/data 40 | {% endif %} 41 | mode: '644' 42 | 43 | - name: Create initial ceph.conf file 44 | ansible.builtin.copy: 45 | dest: "{{ initial_ceph_conf }}" 46 | content: | 47 | [global] 48 | osd_crush_chooseleaf_type = 0 49 | osd pool default size = 1 50 | [mon] 51 | mon_warn_on_pool_no_redundancy = false 52 | [mgr] 53 | mgr/cephadm/log_to_cluster_level = debug 54 | mode: '644' 55 | 56 | - name: Create Ceph Spec file via tripleo-operator-ansible 57 | collections: 58 | - tripleo.operator 59 | ansible.builtin.include_role: 60 | name: tripleo_ceph_spec 61 | vars: 62 | tripleo_ceph_spec_standalone: true 63 | tripleo_ceph_spec_overwrite: true 64 | tripleo_ceph_spec_mon_ip: "{{ mon_ip }}" 65 | tripleo_ceph_spec_stack: "{{ stack }}" 66 | tripleo_ceph_spec_file: "{{ ceph_spec }}" 67 | tripleo_ceph_spec_osd_spec: "{{ osd_spec }}" 68 | tripleo_ceph_spec_debug: true 69 | tripleo_ceph_spec_generate_scripts: true 70 | tripleo_ceph_spec_become: true 71 | 72 | - name: Create ceph-admin user via tripleo-operator-ansible 73 | collections: 74 | - tripleo.operator 75 | ansible.builtin.include_role: 76 | name: tripleo_ceph_user 77 | vars: 78 | tripleo_ceph_user_spec: "{{ ceph_spec }}" 79 | tripleo_ceph_user_enable: true 80 | tripleo_ceph_user_stack: "{{ stack }}" 81 | tripleo_ceph_user_standalone: true 82 | tripleo_ceph_user_debug: true 83 | tripleo_ceph_user_generate_scripts: true 84 | tripleo_ceph_user_become: true 85 | 86 | - name: Deploy Ceph via tripleo-operator-ansible 87 | collections: 88 | - tripleo.operator 89 | ansible.builtin.include_role: 90 | name: tripleo_ceph_deploy 91 | vars: 92 | tripleo_ceph_deploy_standalone: true 93 | tripleo_ceph_deploy_single_host_defaults: true 94 | tripleo_ceph_deploy_skip_user_create: true 95 | tripleo_ceph_deploy_skip_hosts_config: true 96 | tripleo_ceph_deploy_skip_container_registry_config: true 97 | tripleo_ceph_deploy_mon_ip: "{{ mon_ip }}" 98 | tripleo_ceph_deploy_spec: "{{ ceph_spec }}" 99 | tripleo_ceph_deploy_stack: "{{ stack }}" 100 | tripleo_ceph_deploy_config: "{{ initial_ceph_conf }}" 101 | tripleo_ceph_deploy_output: "{{ deployed_ceph }}" 102 | tripleo_ceph_deploy_container_image_prepare: "{{ containers_prep }}" 103 | tripleo_ceph_deploy_cephadm_extra_args: "--log-to-file --skip-mon-network" 104 | tripleo_ceph_deploy_force: true 105 | tripleo_ceph_deploy_become: true 106 | tripleo_ceph_deploy_overwrite: true 107 | tripleo_ceph_deploy_debug: true 108 | tripleo_ceph_deploy_generate_scripts: true 109 | tripleo_ceph_deploy_network_data: "{{ network_data }}" 110 | tripleo_ceph_deploy_cluster_network_name: storage 111 | tripleo_ceph_deploy_with_ntp: "{{ ntp_server is defined | ternary(true, false) }}" 112 | tripleo_ceph_deploy_ntp_server: "{{ ntp_server | default(omit) }}" 113 | tripleo_ceph_deploy_cluster: "{{ (dcn_az is not defined or (dcn_az is defined and dcn_az == 'central')) | ternary('', dcn_az) }}" 114 | 115 | - name: Add ceph to enabled services 116 | ansible.builtin.set_fact: 117 | service_envs: "{{ service_envs | union(ceph_env) }}" 118 | vars: 119 | ceph_env: 120 | - "/usr/share/openstack-tripleo-heat-templates/environments/{{ ceph_env_base }}/{{ ceph_env_name }}.yaml" 121 | 122 | - name: Add ceph network to enabled services 123 | when: ceph_adm_enabled 124 | ansible.builtin.set_fact: 125 | service_envs: "{{ service_envs | union(deployed_ceph_envs) }}" 126 | vars: 127 | deployed_ceph_envs: 128 | - "{{ deployed_ceph }}" 129 | -------------------------------------------------------------------------------- /playbooks/local_os_client.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: stack 5 | gather_facts: false 6 | vars_files: vars/defaults.yaml 7 | name: Grab the remote clouds.yaml 8 | tasks: 9 | - name: Read clouds.yaml from standalone host 10 | ansible.builtin.slurp: 11 | src: /home/stack/.config/openstack/clouds.yaml 12 | register: cloudsyaml 13 | 14 | - name: Create fact for cloudsyaml 15 | ansible.builtin.set_fact: 16 | cloudsyaml: "{{ cloudsyaml['content'] | b64decode | from_yaml }}" 17 | 18 | - name: Grab the CA certificate 19 | when: ssl_enabled 20 | block: 21 | - name: Read CA certificate 22 | ansible.builtin.slurp: 23 | src: "{{ ssl_ca_cert_path }}" 24 | register: ssl_ca_cert_output 25 | - name: Set fact for CA cert 26 | ansible.builtin.set_fact: 27 | ssl_ca_cert: "{{ ssl_ca_cert_output['content'] | b64decode }}" 28 | - name: Copy CA cert into PKI 29 | when: update_local_pki 30 | become: true 31 | become_user: root 32 | delegate_to: localhost 33 | ansible.builtin.copy: 34 | dest: "{{ ssl_ca_cert_path }}" 35 | content: "{{ ssl_ca_cert }}" 36 | mode: '444' 37 | owner: root 38 | group: root 39 | - name: Update CA trust # noqa no-changed-when 40 | when: update_local_pki 41 | become: true 42 | become_user: root 43 | delegate_to: localhost 44 | ansible.builtin.command: update-ca-trust extract 45 | 46 | - hosts: localhost 47 | gather_facts: false 48 | vars_files: vars/defaults.yaml 49 | name: Configure the local clouds.yaml 50 | tasks: 51 | - name: Load Ansible env 52 | ansible.builtin.setup: 53 | filter: ansible_env 54 | 55 | - name: Ensure ~/.config/openstack dir exists 56 | ansible.builtin.file: 57 | path: "{{ ansible_env.HOME }}/.config/openstack" 58 | state: directory 59 | mode: '755' 60 | 61 | - name: Set path of local clouds.yaml 62 | ansible.builtin.set_fact: 63 | cloudsyamlpath: "{{ ansible_env.HOME }}/.config/openstack/clouds.yaml" 64 | 65 | - name: Initialise cloudsyaml 66 | block: 67 | - name: Read local cloudsyaml 68 | ansible.builtin.set_fact: 69 | cloudsyaml: "{{ lookup('file', cloudsyamlpath) | from_yaml }}" 70 | rescue: 71 | - name: Initialise empty cloudsyaml 72 | ansible.builtin.set_fact: 73 | cloudsyaml: "{{ {'clouds': {}} }}" 74 | 75 | - name: Configure cacert locally 76 | when: ssl_enabled 77 | block: 78 | - name: Set local path of cacert 79 | ansible.builtin.set_fact: 80 | cacert_path: "{{ ansible_env.HOME }}/.config/openstack/{{ local_cloudname }}-ca.crt" 81 | 82 | - name: Copy CA cert into local config directory 83 | ansible.builtin.copy: 84 | dest: "{{ cacert_path }}" 85 | content: "{{ hostvars['standalone']['ssl_ca_cert'] }}" 86 | mode: '644' 87 | 88 | - name: Set cacert in clouds.yaml 89 | ansible.builtin.set_fact: 90 | set_cacert: "{{ {'cacert': cacert_path} }}" 91 | 92 | - name: Don't set cacert in clouds.yaml 93 | when: not ssl_enabled 94 | ansible.builtin.set_fact: 95 | vars: 96 | set_cacert: {} 97 | 98 | - name: Merge standalone from remote clouds.yaml into local clouds.yaml entry {{ local_cloudname }} 99 | ansible.builtin.set_fact: 100 | cloudsyaml: "{{ cloudsyaml | combine({'clouds': {local_cloudname: standalone}}, recursive=true) }}" 101 | vars: 102 | standalone: "{{ hostvars['standalone']['cloudsyaml']['clouds']['standalone'] | combine(set_cacert) }}" 103 | when: "'standalone' in hostvars['standalone']['cloudsyaml']['clouds']" 104 | 105 | - name: Merge openshift from remote clouds.yaml into local clouds.yaml entry {{ local_cloudname }} 106 | ansible.builtin.set_fact: 107 | cloudsyaml: "{{ cloudsyaml | combine({'clouds': {local_cloudname + '_openshift': openshift}}, set_cacert, recursive=true) }}" 108 | vars: 109 | openshift: "{{ hostvars['standalone']['cloudsyaml']['clouds']['openshift'] | combine(set_cacert) }}" 110 | when: "'openshift' in hostvars['standalone']['cloudsyaml']['clouds']" 111 | 112 | - name: Update local clouds.yaml 113 | ansible.builtin.copy: 114 | dest: "{{ cloudsyamlpath }}" 115 | content: "{{ cloudsyaml | to_nice_yaml }}" 116 | mode: '0755' 117 | 118 | - name: Install openstack client locally 119 | ansible.builtin.pip: 120 | name: python-openstackclient 121 | extra_args: "{% if not is_local_virtualenv %} --user {% endif %}" 122 | 123 | - name: Create the scripts if it does not exist 124 | ansible.builtin.file: 125 | path: ../scripts 126 | state: directory 127 | mode: '755' 128 | 129 | - name: Write sshuttle script 130 | ansible.builtin.template: 131 | src: sshuttle-standalone.sh.j2 132 | dest: ../scripts/sshuttle-standalone.sh 133 | mode: '0755' 134 | 135 | - name: Write openstack environment script 136 | ansible.builtin.template: 137 | src: env.sh.j2 138 | dest: ../scripts/env.sh 139 | mode: '0644' 140 | 141 | - name: Print useful infos 142 | ansible.builtin.debug: 143 | msg: 144 | - "{{ cloudsyamlpath }} has been updated." 145 | - "To connect to your cloud set OS_CLOUD={{ local_cloudname }} and update your local routes." 146 | - "For convenience:" 147 | - " `scripts/sshuttle-standalone.sh` will start a correctly configure sshuttle." 148 | - " `source scripts/env.sh` will set OS_CLOUD correctly." 149 | -------------------------------------------------------------------------------- /playbooks/network.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: root 5 | gather_facts: true 6 | vars_files: vars/defaults.yaml 7 | roles: 8 | - network_info 9 | name: Configure the network 10 | tasks: 11 | - name: Install ovs tools 12 | ansible.builtin.yum: 13 | state: installed 14 | name: 15 | - rhosp-openvswitch 16 | - NetworkManager-ovs 17 | - nmstate 18 | - iptables 19 | register: installovs 20 | 21 | - name: Restart NetworkManager to load ovs plugin # noqa no-handler 22 | ansible.builtin.systemd: 23 | name: "NetworkManager.service" 24 | enabled: true 25 | state: restarted 26 | when: installovs.changed 27 | 28 | - name: Start openvswitch 29 | ansible.builtin.systemd: 30 | name: openvswitch.service 31 | enabled: true 32 | state: started 33 | 34 | - name: Define dummy interfaces to be created when not using DPDK 35 | when: 36 | - dpdk_interface is not defined 37 | ansible.builtin.set_fact: 38 | nmstate_ifs: | 39 | - name: dummy0 40 | type: dummy 41 | state: up 42 | ipv4: 43 | enabled: false 44 | ipv6: 45 | enabled: false 46 | - name: dummy1 47 | type: dummy 48 | state: up 49 | ipv4: 50 | enabled: false 51 | ipv6: 52 | enabled: false 53 | 54 | - name: Define dummy interfaces to be created when using DPDK 55 | when: 56 | - dpdk_interface is defined 57 | ansible.builtin.set_fact: 58 | nmstate_ifs: | 59 | - name: dummy0 60 | type: dummy 61 | state: up 62 | ipv4: 63 | enabled: true 64 | address: 65 | - ip: {{ local_ip }} 66 | prefix-length: {{ control_plane_prefix | int }} 67 | ipv6: 68 | enabled: false 69 | 70 | # this saves the static route configuration including the default route 71 | # prior to filtering later 72 | 73 | - name: Save route info # noqa no-changed-when 74 | ansible.builtin.command: nmstatectl show --json 75 | register: pre 76 | 77 | - name: Create fact for nmstate_routes 78 | ansible.builtin.set_fact: 79 | nmstate_routes: "{{ pre.stdout | from_json | json_query(q) }}" 80 | vars: 81 | q: "routes.config" 82 | 83 | # This works round a TripleO installation failure caused by NM-managed 84 | # interfaces 'failing' because: 85 | # * The default NM configuration specifies DHCP 86 | # * They have an active link, but 87 | # * The network they are plugged into doesn't have DHCP 88 | # 89 | # To work round this we remove all interfaces from NM control except the 90 | # public interface. 91 | # 92 | # The public interface will also be remove from NM control later by TripleO, 93 | # but we don't touch it here because: 94 | # * We are confident that it is correctly configured in NM because we're 95 | # connected over it 96 | # * We need it for installation 97 | - name: Remove all physical nics from NM control except the public interface 98 | ansible.builtin.set_fact: 99 | nmstate_ifs: "{{ nmstate_ifs | from_yaml + [{'name': item} | combine(removed)] }}" 100 | loop: "{{ physical_nics | difference(primary_nic) }}" 101 | vars: 102 | primary_nic: "{{ [network_info.public_ipv4.interface] }}" 103 | removed: 104 | state: absent 105 | 106 | - name: Log target nmstate 107 | ansible.builtin.debug: 108 | var: nmstate_ifs 109 | 110 | - name: Set nmstate # noqa no-changed-when 111 | ansible.builtin.command: nmstatectl apply --no-commit --timeout 60 112 | args: 113 | stdin: "{{ network_state | to_nice_json }}" 114 | vars: 115 | network_state: 116 | interfaces: "{{ nmstate_ifs }}" 117 | # add saved static routes 118 | routes: 119 | config: "{{ nmstate_routes }}" 120 | register: nmstateset 121 | 122 | - name: Set fact for nmstate checkpoing on RHEL8 123 | when: 124 | - ansible_facts.distribution_major_version == "8" 125 | ansible.builtin.set_fact: 126 | checkpoint: "{{ (nmstateset.stdout_lines | last).split()[1] }}" 127 | 128 | - name: Set fact for nmstate checkpoing on RHEL9 129 | when: 130 | - ansible_facts.distribution_major_version == "9" 131 | ansible.builtin.set_fact: 132 | checkpoint: "{{ (nmstateset.stderr_lines | last).split()[-1] }}" 133 | 134 | - name: Fail if the checkpoint has not been found or is incorrect 135 | when: 136 | - '"/org/freedesktop/NetworkManager/Checkpoint/" not in checkpoint' 137 | ansible.builtin.fail: 138 | msg: "nmstate checkpoint was not found or is incorrect: {{ checkpoint }}" 139 | 140 | # Doing this in 2 steps means that we'll automatically rollback if we break 141 | # networking such that ansible can no longer connect 142 | - name: Commit the new network state # noqa no-changed-when 143 | ansible.builtin.command: "nmstatectl commit {{ checkpoint }}" 144 | 145 | # We have seen this creating a CentOS VM in OpenStack. We don't understand 146 | # why they are created. Specifically we see a phantom ens3 device. It's 147 | # possible they are baked into the image? 148 | # 149 | # nmstate doesn't report them, so we can't use nmstate to delete them. 150 | # 151 | # They cause installation failure due to the failure of the connection to 152 | # come up. 153 | - name: Get a list of phantom NM connections with no associated device # noqa no-changed-when 154 | ansible.builtin.shell: | 155 | set -o pipefail 156 | nmcli -g uuid,device connection | awk -F: '$2 == "" {print $1}' 157 | register: phantom_connections 158 | changed_when: false 159 | 160 | - name: Delete phantom NM connections # noqa no-changed-when 161 | ansible.builtin.command: nmcli connection delete uuid "{{ item }}" 162 | loop: "{{ phantom_connections.stdout_lines }}" 163 | 164 | # This prevents OpenStack installation failure later if the network unit 165 | # failed because not all physical interfaces have DHCP 166 | - name: Ensure network systemd unit is up 167 | ansible.builtin.systemd: 168 | name: network 169 | state: started 170 | 171 | - name: Set fact for public nic when DPDK is disabled 172 | ansible.builtin.set_fact: 173 | public_nic: br-ex 174 | when: 175 | - dpdk_interface is not defined 176 | 177 | - name: Set fact for public nic when DPDK is enabled 178 | ansible.builtin.set_fact: 179 | public_nic: "{{ network_info.public_ipv4.interface }}" 180 | when: 181 | - dpdk_interface is defined 182 | 183 | - name: Configure SNAT for hostonly 184 | ansible.builtin.include_role: 185 | name: snat 186 | vars: 187 | network_name: hostonly 188 | network_cidr: "{{ hostonly_cidr }}" 189 | public_ip: "{{ network_info.public_ipv4.address }}" 190 | 191 | - name: Configure SNAT for hostonly_sriov 192 | ansible.builtin.include_role: 193 | name: snat 194 | vars: 195 | network_name: hostonly-sriov 196 | network_cidr: "{{ hostonly_sriov_cidr }}" 197 | public_ip: "{{ network_info.public_ipv4.address }}" 198 | when: 199 | - sriov_interface is defined 200 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_ovs_dpdk/library/openvswitch_db.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf-8 -*- 3 | 4 | # 5 | # (c) 2015, Mark Hamilton 6 | # Portions copyright @ 2015 VMware, Inc. 7 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'network'} 14 | 15 | 16 | DOCUMENTATION = """ 17 | --- 18 | module: openvswitch_db 19 | author: "Mark Hamilton (@markleehamilton) " 20 | version_added: 2.0 21 | short_description: Configure open vswitch database. 22 | requirements: [ "ovs-vsctl >= 2.3.3" ] 23 | description: 24 | - Set column values in record in database table. 25 | options: 26 | state: 27 | required: false 28 | description: 29 | - Configures the state of the key. When set 30 | to I(present), the I(key) and I(value) pair will be set 31 | on the I(record) and when set to I(absent) the I(key) 32 | will not be set. 33 | default: present 34 | choices: ['present', 'absent'] 35 | version_added: "2.4" 36 | table: 37 | required: true 38 | description: 39 | - Identifies the table in the database. 40 | record: 41 | required: true 42 | description: 43 | - Identifies the record in the table. 44 | col: 45 | required: true 46 | description: 47 | - Identifies the column in the record. 48 | key: 49 | required: false 50 | description: 51 | - Identifies the key in the record column, when the column is a map 52 | type. 53 | value: 54 | required: false 55 | description: 56 | - Expected value for the table, record, column and key. 57 | - Required when I(state) is I(present) 58 | timeout: 59 | required: false 60 | default: 5 61 | description: 62 | - How long to wait for ovs-vswitchd to respond 63 | """ 64 | 65 | EXAMPLES = ''' 66 | # Increase the maximum idle time to 50 seconds before pruning unused kernel 67 | # rules. 68 | - openvswitch_db: 69 | table: open_vswitch 70 | record: . 71 | col: other_config 72 | key: max-idle 73 | value: 50000 74 | 75 | # Disable in band copy 76 | - openvswitch_db: 77 | table: Bridge 78 | record: br-int 79 | col: other_config 80 | key: disable-in-band 81 | value: true 82 | 83 | # Remove in band key 84 | - openvswitch_db: 85 | state: absent 86 | table: Bridge 87 | record: br-int 88 | col: other_config 89 | key: disable-in-band 90 | 91 | # Mark port with tag 10 92 | - openvswitch_db: 93 | table: Port 94 | record: port0 95 | col: tag 96 | value: 10 97 | ''' 98 | import re 99 | 100 | from ansible.module_utils.basic import AnsibleModule 101 | 102 | # Regular expression for map type, must not be empty 103 | NON_EMPTY_MAP_RE = re.compile(r'{.+}') 104 | # Regular expression for a map column type 105 | MAP_RE = re.compile(r'{.*}') 106 | 107 | 108 | def map_obj_to_commands(want, have, module): 109 | """ Define ovs-vsctl command to meet desired state """ 110 | commands = list() 111 | 112 | if module.params['state'] == 'absent': 113 | if 'key' in have.keys(): 114 | templatized_command = "%(ovs-vsctl)s -t %(timeout)s remove %(table)s %(record)s " \ 115 | "%(col)s %(key)s" 116 | # Append the value only when provided 117 | if 'value' in want.keys(): 118 | templatized_command += "=%(value)s" 119 | commands.append(templatized_command % module.params) 120 | elif module.params['key'] is None: 121 | templatized_command = "%(ovs-vsctl)s -t %(timeout)s remove %(table)s %(record)s " \ 122 | "%(col)s" 123 | commands.append(templatized_command % module.params) 124 | else: 125 | if want == have: 126 | # Nothing to commit 127 | return commands 128 | if module.params['key'] is None: 129 | templatized_command = "%(ovs-vsctl)s -t %(timeout)s set %(table)s %(record)s " \ 130 | "%(col)s=%(value)s" 131 | commands.append(templatized_command % module.params) 132 | else: 133 | templatized_command = "%(ovs-vsctl)s -t %(timeout)s set %(table)s %(record)s " \ 134 | "%(col)s:%(key)s=%(value)s" 135 | commands.append(templatized_command % module.params) 136 | 137 | return commands 138 | 139 | 140 | def map_config_to_obj(module): 141 | templatized_command = "%(ovs-vsctl)s -t %(timeout)s list %(table)s %(record)s" 142 | command = templatized_command % module.params 143 | rc, out, err = module.run_command(command, check_rc=True) 144 | if rc != 0: 145 | module.fail_json(msg=err) 146 | 147 | match = re.search(r'^' + module.params['col'] + r'(\s+):(\s+)(.*)$', out, re.M) 148 | 149 | col_value = match.group(3) 150 | 151 | # Map types require key argument 152 | has_key = module.params['key'] is not None 153 | is_map = MAP_RE.match(col_value) 154 | if is_map and not has_key: 155 | module.fail_json( 156 | msg="missing required arguments: key for map type of column") 157 | 158 | col_value_to_dict = {} 159 | if NON_EMPTY_MAP_RE.match(col_value): 160 | for kv in col_value[1:-1].split(', '): 161 | k, v = kv.split('=', 1) 162 | col_value_to_dict[k.strip()] = v.strip('\"') 163 | 164 | obj = { 165 | 'table': module.params['table'], 166 | 'record': module.params['record'], 167 | 'col': module.params['col'], 168 | } 169 | 170 | if has_key and is_map: 171 | if module.params['key'] in col_value_to_dict: 172 | obj['key'] = module.params['key'] 173 | obj['value'] = col_value_to_dict[module.params['key']] 174 | else: 175 | obj['value'] = str(col_value.strip()) 176 | 177 | return obj 178 | 179 | 180 | def map_params_to_obj(module): 181 | obj = { 182 | 'table': module.params['table'], 183 | 'record': module.params['record'], 184 | 'col': module.params['col'], 185 | } 186 | 187 | if module.params['value'] is not None: 188 | if module.params['value'] in ['True', 'False']: 189 | module.params['value'] = module.params['value'].lower() 190 | obj['value'] = module.params['value'] 191 | 192 | key = module.params['key'] 193 | if key is not None: 194 | obj['key'] = key 195 | 196 | return obj 197 | 198 | 199 | def main(): 200 | """ Entry point for ansible module. """ 201 | argument_spec = { 202 | 'state': {'default': 'present', 'choices': ['present', 'absent']}, 203 | 'table': {'required': True}, 204 | 'record': {'required': True}, 205 | 'col': {'required': True}, 206 | 'key': {'required': False}, 207 | 'value': {'required': False, 'type': 'str'}, 208 | 'timeout': {'default': 5, 'type': 'int'}, 209 | } 210 | 211 | required_if = [('state', 'present', ['value'])] 212 | 213 | module = AnsibleModule(argument_spec=argument_spec, 214 | required_if=required_if, 215 | supports_check_mode=True) 216 | 217 | result = {'changed': False} 218 | 219 | # We add ovs-vsctl to module_params to later build up templatized commands 220 | module.params["ovs-vsctl"] = module.get_bin_path("ovs-vsctl", True) 221 | 222 | want = map_params_to_obj(module) 223 | have = map_config_to_obj(module) 224 | 225 | commands = map_obj_to_commands(want, have, module) 226 | result['commands'] = commands 227 | 228 | if commands: 229 | if not module.check_mode: 230 | for c in commands: 231 | module.run_command(c, check_rc=True) 232 | result['changed'] = True 233 | 234 | module.exit_json(**result) 235 | 236 | 237 | if __name__ == '__main__': 238 | main() 239 | -------------------------------------------------------------------------------- /playbooks/templates/standalone_parameters.yaml.j2: -------------------------------------------------------------------------------- 1 | #vi:syntax=yaml 2 | 3 | {% if dcn_az is defined %} 4 | resource_registry: 5 | OS::TripleO::Services::NovaAZConfig: /usr/share/openstack-tripleo-heat-templates/deployment/nova/nova-az-config.yaml 6 | {% if dcn_az != 'central' %} 7 | OS::TripleO::Services::CinderVolume: /usr/share/openstack-tripleo-heat-templates/deployment/cinder/cinder-volume-container-puppet.yaml 8 | OS::TripleO::Services::Etcd: /usr/share/openstack-tripleo-heat-templates/deployment/etcd/etcd-container-puppet.yaml 9 | OS::TripleO::Services::CACerts: OS::Heat::None 10 | OS::TripleO::Services::CinderApi: OS::Heat::None 11 | OS::TripleO::Services::CinderScheduler: OS::Heat::None 12 | OS::TripleO::Services::Clustercheck: OS::Heat::None 13 | OS::TripleO::Services::GlanceApi: OS::Heat::None 14 | OS::TripleO::Services::HAproxy: OS::Heat::None 15 | OS::TripleO::Services::Horizon: OS::Heat::None 16 | OS::TripleO::Services::Keystone: OS::Heat::None 17 | OS::TripleO::Services::Memcached: OS::Heat::None 18 | OS::TripleO::Services::MySQL: OS::Heat::None 19 | OS::TripleO::Services::NeutronApi: OS::Heat::None 20 | OS::TripleO::Services::NeutronDhcpAgent: OS::Heat::None 21 | OS::TripleO::Services::NovaApi: OS::Heat::None 22 | OS::TripleO::Services::NovaConductor: OS::Heat::None 23 | OS::TripleO::Services::NovaConsoleauth: OS::Heat::None 24 | OS::TripleO::Services::NovaIronic: OS::Heat::None 25 | OS::TripleO::Services::NovaMetadata: OS::Heat::None 26 | OS::TripleO::Services::NovaPlacement: OS::Heat::None 27 | OS::TripleO::Services::NovaScheduler: OS::Heat::None 28 | OS::TripleO::Services::NovaVncProxy: OS::Heat::None 29 | OS::TripleO::Services::OVNDBs: OS::Heat::None 30 | OS::TripleO::Services::OsloMessagingNotify: OS::Heat::None 31 | OS::TripleO::Services::OsloMessagingRpc: OS::Heat::None 32 | OS::TripleO::Services::Pacemaker: OS::Heat::None 33 | OS::TripleO::Services::PlacementApi: OS::Heat::None 34 | OS::TripleO::Services::Pacemaker: OS::Heat::None 35 | OS::TripleO::Services::Redis: OS::Heat::None 36 | OS::TripleO::Services::SwiftProxy: OS::Heat::None 37 | OS::TripleO::Services::SwiftRingBuilder: OS::Heat::None 38 | OS::TripleO::Services::SwiftStorage: OS::Heat::None 39 | {% endif %} 40 | {% endif %} 41 | {% if extra_heat_resource_registry is defined %} 42 | resource_registry: 43 | {% for key, value in extra_heat_resource_registry.items() %} 44 | {{ key }}: {{ value }} 45 | {% endfor %} 46 | {% endif %} 47 | parameter_defaults: 48 | CloudName: {{ hostname }}.{{ clouddomain }} 49 | ContainerCli: podman 50 | Debug: true 51 | DeploymentUser: {{ ansible_env.USER }} 52 | DnsServers: 53 | {% for nameserver in network_info.dns %} 54 | - {{ nameserver }} 55 | {% endfor %} 56 | # needed for vip & pacemaker 57 | KernelIpNonLocalBind: 1 58 | # For OSP16 59 | ExtraSysctlSettings: 60 | net.ipv6.conf.all.forwarding: 61 | value: 1 62 | # For OSP17 and beyond 63 | KernelIpv6ConfAllForwarding: 1 64 | DockerInsecureRegistryAddress: 65 | - {{ control_plane_ip }}:8787 66 | # domain name used by the host 67 | CloudDomain: {{ clouddomain }} 68 | NeutronDnsDomain: {{ clouddomain }} 69 | NeutronBridgeMappings: {{ neutron_bridge_mappings }} 70 | NeutronFlatNetworks: {{ neutron_flat_networks }} 71 | NeutronGlobalPhysnetMtu: {{ neutron_mtu }} 72 | {% if sriov_interface is defined %} 73 | OVNCMSOptions: "enable-chassis-as-gw" 74 | {% if neutron_physical_dev_mappings is defined %} 75 | NeutronPhysicalDevMappings: {{ neutron_physical_dev_mappings }} 76 | {% else %} 77 | NeutronPhysicalDevMappings: "hostonly-sriov:{{ sriov_interface }}" 78 | {% endif %} 79 | NovaPCIPassthrough: {{sriov_nova_pci_passthrough | mandatory | to_json }} 80 | {% endif %} 81 | {% if dpdk_interface is defined %} 82 | NovaLibvirtRxQueueSize: 1024 83 | NovaLibvirtTxQueueSize: 1024 84 | VhostuserSocketGroup: "hugetlbfs" 85 | {% endif %} 86 | {% if tuned_isolated_cores is defined %} 87 | IsolCpusList: {{ tuned_isolated_cores }} 88 | TunedProfileName: "cpu-partitioning" 89 | {% endif %} 90 | {% if kernel_args is defined %} 91 | KernelArgs: "{{ kernel_args }}" 92 | {% endif %} 93 | StandaloneEnableRoutedNetworks: false 94 | StandaloneHomeDir: "{{ ansible_env.HOME }}" 95 | InterfaceLocalMtu: 1500 96 | SELinuxMode: permissive 97 | # For OSP17+: 98 | StandaloneNetworkConfigTemplate: "{{ ansible_env.HOME }}/dev-install_net_config.yaml" 99 | # For OSP16: 100 | StandaloneNetConfigOverride: 101 | network_config: 102 | {% for member in net_config_json['network_config'] %} 103 | - {{ member }} 104 | {% endfor %} 105 | OctaviaGenerateCerts: true 106 | OctaviaCaKeyPassphrase: "secrete" 107 | OctaviaAmphoraSshKeyFile: "{{ ansible_env.HOME }}/octavia.pub" 108 | OctaviaAmphoraImageFilename: "{{ ansible_env.HOME }}/amphora.qcow2" 109 | BarbicanSimpleCryptoGlobalDefault: true 110 | CinderApiPolicies: 111 | cinder-vol-state-set: 112 | key: "volume_extension:volume_admin_actions:reset_status" 113 | value: "rule:admin_or_owner" 114 | cinder-vol-force-detach: 115 | key: "volume_extension:volume_admin_actions:force_detach" 116 | value: "rule:admin_or_owner" 117 | # We never want the node to reboot during tripleo deploy, but defer to later 118 | KernelArgsDeferReboot: true 119 | StandaloneExtraGroupVars: 120 | tripleo_kernel_defer_reboot: true 121 | 122 | {% if ceph_enabled %} 123 | {% if not ceph_adm_enabled %} 124 | {% include "standalone_parameters.ceph_ansible.yaml.j2" %} 125 | {% endif %} 126 | 127 | NovaComputeStartupDelay: 180 128 | 129 | # Don't use ceph for local ephemeral storage by default: its performance is 130 | # generally not good enough for etcd on a dev-install setup. 131 | NovaEnableRbdBackend: false 132 | {% endif %} 133 | 134 | # Configure Nova to use preallocated raw disks for consistent storage 135 | # performance. 136 | NovaComputeUseCowImages: false 137 | NovaComputeLibvirtPreAllocateImages: space 138 | 139 | {% if admin_password is defined %} 140 | AdminPassword: {{ admin_password }} 141 | {% endif %} 142 | {% if rhsm_enabled %} 143 | {% if ntp_server is defined %} 144 | NtpServer: {{ ntp_server }} 145 | {% endif %} 146 | ContainerImageRegistryCredentials: 147 | # assume first registry 148 | {{ registers.0.name | ansible.builtin.mandatory}}: 149 | {{ registers.0.username | ansible.builtin.mandatory | ansible.builtin.quote }}: {{ registers.0.password | ansible.builtin.mandatory | ansible.builtin.quote }} 150 | ContainerImageRegistryLogin: true 151 | {% endif %} 152 | {% if ssl_enabled %} 153 | AddVipsToEtcHosts: true 154 | HorizonSecureCookies: True 155 | SSLCertificate: | 156 | {{ ssl_cert | indent }} 157 | SSLKey: | 158 | {{ ssl_key | indent }} 159 | SSLRootCertificate: | 160 | {{ ssl_ca_cert | indent }} 161 | PublicTLSCAFile: {{ ssl_ca_cert_path }} 162 | {% endif %} 163 | {% if dcn_az is defined %} 164 | {% if dcn_az == 'central' %} 165 | NovaSchedulerDiscoverHostsInCellsInterval: 120 166 | GlanceBackendID: central 167 | GlanceEnabledImportMethods: web-download,copy-image 168 | GlanceStoreDescription: 'central rbd glance store' 169 | {% else %} 170 | # BZ#1901143 and BZ#1903005 171 | CephClusterName: {{ dcn_az }} 172 | {% endif %} 173 | CinderStorageAvailabilityZone: {{ dcn_az }} 174 | NeutronDefaultAvailabilityZones: {{ dcn_az }} 175 | NovaComputeAvailabilityZone: {{ dcn_az }} 176 | NovaCrossAZAttach: false 177 | OVNCMSOptions: "enable-chassis-as-gw,availability-zones={{ dcn_az }}" 178 | {% endif %} 179 | {% if standalone_extra_config|length > 0 or dcn_az is defined or manila_enabled %} 180 | StandaloneExtraConfig: 181 | {% if dcn_az is defined %} 182 | nova::availability_zone::default_schedule_zone: {{ dcn_az }} 183 | oslo_messaging_notify_use_ssl: false 184 | oslo_messaging_rpc_use_ssl: false 185 | {% endif %} 186 | {% if manila_enabled %} 187 | ganesha_vip: "{{ public_api }}" 188 | # for cephadm support on OSP 17 189 | tripleo_cephadm_ceph_nfs_bind_addr: "{{ public_api }}" 190 | {% endif %} 191 | {% if standalone_extra_config|length > 0 %} 192 | {% for key, value in standalone_extra_config.items() %} 193 | {{ key }}: {{ value }} 194 | {% endfor %} 195 | {% endif %} 196 | {% endif %} 197 | {# note: keep this block at the very end #} 198 | {% if extra_heat_params is defined %} 199 | {% for key, value in extra_heat_params.items() %} 200 | {{ key }}: {{ value }} 201 | {% endfor %} 202 | {% endif %} 203 | -------------------------------------------------------------------------------- /playbooks/roles/tripleo_ovs_dpdk/tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright 2019 Red Hat, Inc. 3 | # All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 6 | # not use this file except in compliance with the License. You may obtain 7 | # a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | # License for the specific language governing permissions and limitations 15 | # under the License. 16 | 17 | - name: Check valid input for tripleo_ovs_dpdk_pmd_core_list 18 | ansible.builtin.fail: 19 | msg: "List of PMD cores cannot be empty - tripleo_ovs_dpdk_pmd_core_list" 20 | when: not tripleo_ovs_dpdk_pmd_core_list|string or tripleo_ovs_dpdk_pmd_core_list == 'null' 21 | 22 | - name: Apply PMD cores config 23 | openvswitch_db: 24 | table: open_vswitch 25 | record: . 26 | col: other_config 27 | key: pmd-cpu-mask 28 | value: "{{ tripleo_ovs_dpdk_pmd_core_list | cpu_mask }}" 29 | when: tripleo_ovs_dpdk_pmd_core_list|string 30 | 31 | - name: Set DPDK lcores config 32 | openvswitch_db: 33 | table: open_vswitch 34 | record: . 35 | col: other_config 36 | key: dpdk-lcore-mask 37 | value: "{{ tripleo_ovs_dpdk_lcore_list | cpu_mask }}" 38 | when: tripleo_ovs_dpdk_lcore_list|string 39 | 40 | - name: Remove DPDK lcores config 41 | openvswitch_db: 42 | state: absent 43 | table: open_vswitch 44 | record: . 45 | col: other_config 46 | key: dpdk-lcore-mask 47 | when: not tripleo_ovs_dpdk_lcore_list|string or tripleo_ovs_dpdk_lcore_list == 'null' 48 | 49 | - name: Add memory channels to dpdk extra 50 | ansible.builtin.set_fact: 51 | tripleo_ovs_dpdk_extra_internal: "{{ tripleo_ovs_dpdk_extra }} -n {{ tripleo_ovs_dpdk_memory_channels }}" 52 | 53 | - name: Apply DPDK extra 54 | openvswitch_db: 55 | table: open_vswitch 56 | record: . 57 | col: other_config 58 | key: dpdk-extra 59 | value: "'{{ tripleo_ovs_dpdk_extra_internal }}'" 60 | 61 | - name: Apply socket-mem and socket-limit config 62 | block: 63 | - openvswitch_db: 64 | table: open_vswitch 65 | record: . 66 | col: other_config 67 | key: dpdk-socket-mem 68 | value: "{{ tripleo_ovs_dpdk_socket_memory }}" 69 | 70 | - openvswitch_db: 71 | table: open_vswitch 72 | record: . 73 | col: other_config 74 | key: dpdk-socket-limit 75 | value: "{{ tripleo_ovs_dpdk_socket_memory }}" 76 | when: tripleo_ovs_dpdk_socket_memory|string 77 | 78 | - name: Remove DPDK socket-mem and socket-limit config 79 | block: 80 | - openvswitch_db: 81 | state: absent 82 | table: open_vswitch 83 | record: . 84 | col: other_config 85 | key: dpdk-socket-mem 86 | 87 | - openvswitch_db: 88 | state: absent 89 | table: open_vswitch 90 | record: . 91 | col: other_config 92 | key: dpdk-socket-limit 93 | when: not tripleo_ovs_dpdk_socket_memory|string or tripleo_ovs_dpdk_socket_memory == 'null' 94 | 95 | - name: Apply Revalidator threads config 96 | openvswitch_db: 97 | table: open_vswitch 98 | record: . 99 | col: other_config 100 | key: n-revalidator-threads 101 | value: "{{ tripleo_ovs_dpdk_revalidator_cores }}" 102 | when: tripleo_ovs_dpdk_revalidator_cores|string 103 | 104 | - name: Remove Revalidator threads config 105 | openvswitch_db: 106 | state: absent 107 | table: open_vswitch 108 | record: . 109 | col: other_config 110 | key: n-revalidator-threads 111 | when: not tripleo_ovs_dpdk_revalidator_cores|string 112 | 113 | - name: Set Handler threads config 114 | openvswitch_db: 115 | table: open_vswitch 116 | record: . 117 | col: other_config 118 | key: n-handler-threads 119 | value: "{{ tripleo_ovs_dpdk_handler_cores }}" 120 | when: tripleo_ovs_dpdk_handler_cores|string 121 | 122 | - name: Remove Handler threads config 123 | openvswitch_db: 124 | state: absent 125 | table: open_vswitch 126 | record: . 127 | col: other_config 128 | key: n-handler-threads 129 | when: not tripleo_ovs_dpdk_handler_cores|string 130 | 131 | - name: Set EMC Insertion Probability config 132 | openvswitch_db: 133 | table: open_vswitch 134 | record: . 135 | col: other_config 136 | key: emc-insert-inv-prob 137 | value: "{{ tripleo_ovs_dpdk_emc_insertion_probablity }}" 138 | when: tripleo_ovs_dpdk_emc_insertion_probablity|string 139 | 140 | - name: Remove EMC Insertion Probability config 141 | openvswitch_db: 142 | state: absent 143 | table: open_vswitch 144 | record: . 145 | col: other_config 146 | key: emc-insert-inv-prob 147 | when: not tripleo_ovs_dpdk_emc_insertion_probablity|string 148 | 149 | - name: Enable TSO in datapath 150 | openvswitch_db: 151 | table: open_vswitch 152 | record: . 153 | col: other_config 154 | key: userspace-tso-enable 155 | value: "{{ tripleo_ovs_dpdk_enable_tso }}" 156 | when: tripleo_ovs_dpdk_enable_tso|bool 157 | 158 | - name: Disable TSO in datapath 159 | openvswitch_db: 160 | state: absent 161 | table: open_vswitch 162 | record: . 163 | col: other_config 164 | key: userspace-tso-enable 165 | when: not tripleo_ovs_dpdk_enable_tso|bool 166 | 167 | - name: Enable postcopy support 168 | when: tripleo_ovs_dpdk_vhost_postcopy_support|bool 169 | block: 170 | - name: Enable vhost-postcopy-support 171 | openvswitch_db: 172 | table: open_vswitch 173 | record: . 174 | col: other_config 175 | key: vhost-postcopy-support 176 | value: "{{ tripleo_ovs_dpdk_vhost_postcopy_support }}" 177 | - name: Disable mlockall in ovs 178 | replace: 179 | path: '/etc/sysconfig/openvswitch' 180 | regexp: '^OPTIONS.*' 181 | replace: 'OPTIONS="{{ tripleo_ovs_dpdk_vhost_postcopy_ovs_options }}"' 182 | 183 | - name: Disable postcopy support 184 | when: not tripleo_ovs_dpdk_vhost_postcopy_support|bool 185 | block: 186 | - name: Disable vhost-postcopy-support 187 | openvswitch_db: 188 | state: absent 189 | table: open_vswitch 190 | record: . 191 | col: other_config 192 | key: vhost-postcopy-support 193 | - name: Return ovs OPTIONS to default 194 | replace: 195 | path: '/etc/sysconfig/openvswitch' 196 | regexp: '^OPTIONS.*' 197 | replace: 'OPTIONS=""' 198 | 199 | - name: Enable DPDK OVS PMD Auto Load Balance 200 | openvswitch_db: 201 | table: open_vswitch 202 | record: . 203 | col: other_config 204 | key: pmd-auto-lb 205 | value: "{{ tripleo_ovs_dpdk_pmd_auto_lb }}" 206 | when: tripleo_ovs_dpdk_pmd_auto_lb|bool 207 | 208 | - name: Disable DPDK OVS PMD Auto Load Balance 209 | openvswitch_db: 210 | state: absent 211 | table: open_vswitch 212 | record: . 213 | col: other_config 214 | key: pmd-auto-lb 215 | when: not tripleo_ovs_dpdk_pmd_auto_lb|bool 216 | 217 | - name: Set minimum PMD thread load threshold 218 | openvswitch_db: 219 | table: open_vswitch 220 | record: . 221 | col: other_config 222 | key: pmd-auto-lb-load-threshold 223 | value: "{{ tripleo_ovs_dpdk_pmd_load_threshold }}" 224 | when: tripleo_ovs_dpdk_pmd_load_threshold|string 225 | 226 | - name: Remove minimum PMD thread load threshold 227 | openvswitch_db: 228 | state: absent 229 | table: open_vswitch 230 | record: . 231 | col: other_config 232 | key: pmd-auto-lb-load-threshold 233 | when: not tripleo_ovs_dpdk_pmd_load_threshold|string 234 | 235 | - name: Set PMD load variance improvement threshold 236 | openvswitch_db: 237 | table: open_vswitch 238 | record: . 239 | col: other_config 240 | key: pmd-auto-lb-improvement-threshold 241 | value: "{{ tripleo_ovs_dpdk_pmd_improvement_threshold }}" 242 | when: tripleo_ovs_dpdk_pmd_improvement_threshold|string 243 | 244 | - name: Remove PMD load variance improvement threshold 245 | openvswitch_db: 246 | state: absent 247 | table: open_vswitch 248 | record: . 249 | col: other_config 250 | key: pmd-auto-lb-improvement-threshold 251 | when: not tripleo_ovs_dpdk_pmd_improvement_threshold|string 252 | 253 | - name: Set PMD auto load balancing interval 254 | openvswitch_db: 255 | table: open_vswitch 256 | record: . 257 | col: other_config 258 | key: pmd-auto-lb-rebal-interval 259 | value: "{{ tripleo_ovs_dpdk_pmd_rebal_interval }}" 260 | when: tripleo_ovs_dpdk_pmd_rebal_interval|string 261 | 262 | - name: Remove PMD auto load balancing interval 263 | openvswitch_db: 264 | state: absent 265 | table: open_vswitch 266 | record: . 267 | col: other_config 268 | key: pmd-auto-lb-rebal-interval 269 | when: not tripleo_ovs_dpdk_pmd_rebal_interval|string 270 | -------------------------------------------------------------------------------- /playbooks/vars/defaults.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | rhos_release: 17.1 3 | hostname: standalone 4 | clouddomain: shiftstack 5 | 6 | # is ansible running in a virtualenv on the control node 7 | is_local_virtualenv: "{{ lookup('env', 'VIRTUAL_ENV') | default('', true) }}" 8 | 9 | # The name of the cloud in *local* clouds.yaml. On the host it will always be 10 | # called `standalone`. 11 | local_cloudname: standalone 12 | 13 | # Keystone password for the 'openshift' user 14 | openshift_password: password 15 | 16 | # Keystone password for the 'admin' user (default is generated by TripleO and secure) 17 | # admin_password 18 | 19 | # Control plane network is used for services not exposed on the public network 20 | # and isolated under the br-ctlplane bridge. 21 | # * local_ip is the IP where the services actually listen to. 22 | # * control_plane_ip is the VIP that will be managed by Pacemaker, 23 | # where HAproxy will listen on the control plane network and 24 | # redirect the traffic to local_ip where the service actually listens. 25 | # You probably won't need to change this. 26 | control_plane_cidr: 192.168.24.0/24 27 | control_plane_prefix: "{{ control_plane_cidr | ansible.utils.ipaddr('prefix') }}" 28 | local_ip: "{{ control_plane_cidr | nthhost(1) }}" 29 | control_plane_ip: "{{ control_plane_cidr | nthhost(2) }}" 30 | 31 | # The IP address of the public openstack endpoints 32 | # By default we use the default IP of the host 33 | public_api: "{{ network_info.public_ipv4.address }}" 34 | 35 | # Whether or not manually create the default route via br-ex, in case it's not applicable via DHCP. 36 | public_default_route: false 37 | 38 | # For advanced network configurations (e.g. SR-IOV), network_config can be overriden 39 | # The format is for os-net-config, check dev-install_net_config.yaml.j2 template. 40 | # network_config 41 | 42 | # List of remote IPs used by VXLAN enpoints to connect both 43 | # hostonly and control plane bridges, when they exist. 44 | tunnel_remote_ips: [] 45 | 46 | # The `external` provider network 47 | # This will be created only if external_fip_pool_start and external_fip_pool_end 48 | # are manually defined. 49 | # By default we assume it shares the same subnet as the default external IP, 50 | # which is true in DSAL. 51 | # N.B. (mdbooth): external_network is not used outside this file, and is not 52 | # required if overriding. 53 | external_netmask: "{{ network_info.public_ipv4.network }}/{{ network_info.public_ipv4.netmask }}" 54 | external_cidr: "{{ external_netmask | ansible.utils.ipaddr('net') }}" 55 | external_gateway: "{{ network_info.public_ipv4.gateway }}" 56 | # external_fip_pool_start 57 | # external_fip_pool_end 58 | 59 | # The `hostonly` dual-stack provider network 60 | # This will always be created. It creates a provider network which is local to 61 | # the host, and not externally routable. 62 | # The routable cidr of the hostonly network, even if we can't use all of it. 63 | hostonly_cidr: 192.168.25.0/24 64 | # The IP of the gateway used by the hostonly provider network, which must be 65 | # within hostonly_cidr. 66 | hostonly_gateway: "{{ hostonly_cidr | nthhost(1) }}" 67 | # The range of allocatable FIPs within hostonly_cidr 68 | hostonly_fip_pool_start: "{{ hostonly_cidr | nthhost(2) }}" 69 | hostonly_fip_pool_end: "{{ hostonly_cidr | nthhost(-2) }}" 70 | # Same for IPv6 71 | hostonly_v6_cidr: 2001:db8::/64 72 | hostonly_v6_gateway: "{{ hostonly_v6_cidr | nthhost(1) }}" 73 | hostonly_v6_fip_pool_start: "{{ hostonly_v6_cidr | nthhost(2) }}" 74 | hostonly_v6_fip_pool_end: "{{ hostonly_v6_cidr | nthhost(-2) }}" 75 | 76 | # `hostonly` variants 77 | hostonly_sriov_cidr: 192.168.26.0/24 78 | hostonly_sriov_gateway: "{{ hostonly_sriov_cidr | nthhost(1) }}" 79 | hostonly_sriov_prefix: "{{ hostonly_sriov_cidr | ansible.utils.ipaddr('prefix') }}" 80 | hostonly_sriov_fip_pool_start: "{{ hostonly_sriov_cidr | nthhost(2) }}" 81 | hostonly_sriov_fip_pool_end: "{{ hostonly_sriov_cidr | nthhost(-2) }}" 82 | 83 | # Configuration used only by prepare_stack_testconfig, which is not run by 84 | # default. 85 | testconfig_private_cidr: 192.168.100.0/24 86 | testconfig_public_key: ~/.ssh/id_rsa.pub 87 | 88 | cirros_url: http://download.cirros-cloud.net/0.5.1/cirros-0.5.1-x86_64-disk.img 89 | 90 | enabled_services: [] 91 | standalone_role: /usr/share/openstack-tripleo-heat-templates/roles/Standalone.yaml 92 | # List of TripleO services that we want to add in the role defined in standalone_role. 93 | # e.g. ['OS::TripleO::Services::CinderVolumeEdge', 'OS::TripleO::Services::Etcd'] 94 | standalone_role_overrides: [] 95 | standalone_extra_config: {} 96 | 97 | # Sets the number of Neutron/Nova/... workers to 1 98 | # Uses the environement file low-memory-usage.yaml 99 | low_memory_usage: false 100 | 101 | # This variable allows to add extra Heat parameters to standalone_parameters.yaml. 102 | # e.g. extra_heat_params: 103 | # NovaReservedHostMemory: 4096 104 | # NovaPCIPassthrough: 105 | # - address: "0000:04:00.1" 106 | # Note that if a Heat param is defined in extra_heat_params and also in standalone_parameters, 107 | # the former will override the latter which can be useful if you need specific configs. 108 | # 109 | # extra_heat_params: 110 | 111 | # This variable allows to add extra resource registry heat resources to standalone_parameters.yaml 112 | # e.g. extra_heat_resource_registry: 113 | # OS::TripleO::Services::HeatEngine: /usr/share/openstack-tripleo-heat-templates/deployment/heat/heat-engine-container-puppet.yaml 114 | # OS::TripleO::Services::HeatApi: /usr/share/openstack-tripleo-heat-templates/deployment/heat/heat-api-container-puppet.yaml 115 | # 116 | # Note that if a Heat resource registry is defined in extra_heat_resource_registry and also in standalone_parameters, 117 | # the former will override the latter which can be useful if you need specific configs. 118 | # 119 | # extra_heat_resource_registry: 120 | 121 | # This param can be overriden, but only when overriding the network_config, otherwise the default 122 | # should work as is: 123 | # neutron_bridge_mappings: 124 | neutron_flat_networks: "external,hostonly,hostonly-sriov" 125 | 126 | # If we have more than one SR-IOV device, it can be useful to override this one, but the default is safe 127 | # if we only use `sriov_interface` for one device. 128 | # neutron_physical_dev_mappings: 129 | 130 | tripleo_repos_repos: 131 | - current-tripleo 132 | - ceph 133 | 134 | ceph_enabled: true 135 | # List of devices to use for ceph. If unset, we use a loop device instead. 136 | # NOTE: on RHEL 9, this has to be a list of disk paths, and not /dev/sdX. 137 | # ceph_devices: 138 | # - /dev/disk/by-path/pci-0000:45:00.0-ata-3 139 | 140 | # It will create a LVM PV from all `ceph_devices` and then 141 | # create a VG and LV. Then the VG will be exposed to Ceph to 142 | # create the OSD on it. 143 | # This can be used to workaround hardware issues like 144 | # reported here: https://bugzilla.redhat.com/show_bug.cgi?id=2235819 145 | ceph_devices_to_lvm: false 146 | 147 | # Size of the loop device that will be 148 | # used for Ceph (in GB). 149 | ceph_loop_device_size: 100 150 | 151 | octavia_enabled: true 152 | 153 | barbican_enabled: false 154 | 155 | manila_enabled: false 156 | # Workaround for BZ#1969962 157 | manila_services: 158 | - OS::TripleO::Services::CephNfs 159 | 160 | # Whether or not we want to add the swiftoperator role to 161 | # the openshift user in openshift project (in Keystone). 162 | # Set this to false and the openshift user won't have access 163 | # to Swift. It can be useful if you want to force OpenShift to 164 | # deploy the Image registry in Cinder instead of Swift. 165 | swiftoperator_enabled: true 166 | 167 | # Enable SSL for the OpenStack public endpoints 168 | ssl_enabled: true 169 | # To use your own certificates and key, set these variables, otherwise 170 | # dev-install will generate self-signed certificates and use them 171 | # ssl_cert 172 | # ssl_key 173 | # If you already have your own CA, you can provide these two variables 174 | # and dev-install will sign the certificates with it. 175 | # If left unset, dev-install will generate the CA and self-sign it. 176 | # ssl_ca_cert 177 | # ssl_ca_key 178 | ssl_ca_cert_path: /etc/pki/ca-trust/source/anchors/simpleca.crt 179 | # Whether or not we update the local PKI with the CA certificate 180 | update_local_pki: false 181 | 182 | sriov_services: 183 | - OS::TripleO::Services::NeutronSriovAgent 184 | 185 | dpdk_services: 186 | - OS::TripleO::Services::ComputeNeutronOvsDpdk 187 | 188 | kernel_services: 189 | - OS::TripleO::Services::BootParams 190 | 191 | # sriov_interface: 192 | # sriov_nic_numvfs: 193 | # sriov_nova_pci_passthrough: 194 | 195 | # dpdk_interface: 196 | # tuned_isolated_cores: 197 | 198 | # Kernel arguments to add at boot 199 | # kernel_args: 200 | 201 | # This should not be changed unless you know what you're doing 202 | # because CentOS stream is now the only distro supported when deploying 203 | # TripleO from upstream. 204 | tripleo_repos_stream: true 205 | 206 | # A list of SSH public keys that will be authorized to be used 207 | # when connecting with the stack user 208 | # They have to be URLs, e.g. https://github.com/foobar.keys 209 | authorized_keys: [] 210 | 211 | # Red Hat Subscription Manager options 212 | rhsm_enabled: false 213 | # If the system is used for production, you want to keep 214 | # RHSM activated to get upgrades later; so in this case set it 215 | # to false. 216 | rhsm_ephemeral: true 217 | rhsm_repos: 218 | - rhel-9-for-x86_64-baseos-eus-rpms 219 | - rhel-9-for-x86_64-appstream-eus-rpms 220 | - rhel-9-for-x86_64-highavailability-eus-rpms 221 | - openstack-17.1-for-rhel-9-x86_64-rpms 222 | - fast-datapath-for-rhel-9-x86_64-rpms 223 | - rhceph-6-tools-for-rhel-9-x86_64-rpms 224 | rhsm_method: "portal" 225 | rhsm_release: 9.2 226 | # Note: to install 16.1 on RHEL 8.2, you need rhsm_container_tools_version set to "2.0" 227 | # For OSP 16.2 on RHEL 8.4, you need "3.0". 228 | rhsm_container_tools_version: '3.0' 229 | # Note: to install 16.1 on RHEL 8.2, you need virt_release set to "8.2" 230 | # For OSP 16.2 on RHEL 8.4, you need "av". 231 | virt_release: av 232 | # Red Hat Registry credentials have to be set when deploying OSP on RHEL. Main 233 | # registry, and all additional one should be defined in a list: 234 | # registers: 235 | # - name: registry.url 236 | # username: joe 237 | # password: secret 238 | 239 | # Edge parameters 240 | # The central site must be named "central", otherwise for other AZs it's up to the user. 241 | # dcn_az 242 | dcn_services: 243 | - OS::TripleO::Services::Etcd 244 | - OS::TripleO::Services::NovaAZConfig 245 | 246 | # A list of block devices which will be combined and used as ephemeral local 247 | # storage 248 | # NOTE: on RHEL 9, this has to be a list of disk paths, and not /dev/sdX. 249 | ephemeral_storage_devices: [] 250 | 251 | # Whether or not we want OVN to be enabled 252 | ovn_enabled: true 253 | 254 | # In multinode, we create VXLAN tunnels to connect the br-ctlplane bridges 255 | # and on top of it, Neutron tenant networks will also have tunnels so 256 | # we need to lower the MTU to 1400 which should be safe to do Geneve tunnels 257 | # over VXLAN. For PEK2 DSAL boxes you might need to have 1350 as apparently 258 | # there are packets flying with 1260 (and 1300 will give you 259 | # 1242 on Neutron network which won't be enough). 260 | # 261 | # The default value can be problematic when doing double encapsulaiton with OVN, 262 | # the value will have to be increased. See the following bug report: 263 | # https://issues.redhat.com/browse/OCPBUGS-2921 264 | neutron_mtu: 1400 265 | ctlplane_mtu: "{{ neutron_mtu | int + 100 }}" 266 | hostonly_mtu: "{{ neutron_mtu | int + 100 }}" 267 | public_mtu: "{{ ctlplane_mtu | int + 100 }}" 268 | 269 | # This is a safe default value for NTP server. 270 | # Usually people don't use RHSM when deploying from the internal RH network, but use 271 | # the puddles; so they'll get our internal NTP server. 272 | ntp_server: "{{ rhsm_enabled | ternary('0.pool.ntp.org', 'clock.redhat.com') }}" 273 | -------------------------------------------------------------------------------- /playbooks/prepare_stack.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: stack 5 | gather_facts: false 6 | vars_files: vars/defaults.yaml 7 | roles: 8 | - network_info 9 | name: Create OpenStack resources 10 | tasks: 11 | - name: Gather host environment variables 12 | ansible.builtin.setup: 13 | filter: ansible_env 14 | 15 | - name: Create openshift user without any admin privileges # noqa no-changed-when 16 | ansible.builtin.shell: | 17 | if ! openstack project show openshift; then 18 | openstack project create openshift 19 | fi 20 | if ! openstack user show openshift; then 21 | openstack user create --password '{{ openshift_password }}' openshift 22 | fi 23 | for r in _member_ member; do 24 | if openstack role show $r; then 25 | openstack role add --user openshift --project openshift $r 26 | fi 27 | done 28 | 29 | # Unlimited quota 30 | openstack quota set \ 31 | --cores -1 \ 32 | --fixed-ips -1 \ 33 | --injected-file-size -1 \ 34 | --injected-files -1 \ 35 | --instances -1 \ 36 | --key-pairs -1 \ 37 | --properties -1 \ 38 | --ram -1 \ 39 | --server-groups -1 \ 40 | --server-group-members -1 \ 41 | --backups -1 \ 42 | --backup-gigabytes -1 \ 43 | --per-volume-gigabytes -1 \ 44 | --snapshots -1 \ 45 | --volumes -1 \ 46 | --floating-ips -1 \ 47 | --secgroup-rules -1 \ 48 | --secgroups -1 \ 49 | --networks -1 \ 50 | --subnets -1 \ 51 | --ports -1 \ 52 | --routers -1 \ 53 | --rbac-policies -1 \ 54 | --subnetpools -1 \ 55 | openshift 56 | 57 | environment: 58 | OS_CLOUD: standalone 59 | 60 | - name: Add swiftoperator role for openshift user # noqa no-changed-when 61 | ansible.builtin.command: openstack role add --user openshift --project openshift swiftoperator 62 | environment: 63 | OS_CLOUD: standalone 64 | when: swiftoperator_enabled 65 | 66 | - name: Create flavors # noqa no-changed-when 67 | ansible.builtin.shell: | 68 | if ! openstack flavor show m1.tiny; then 69 | openstack flavor create --ram 1024 --disk 10 --vcpu 1 --ephemeral 1 --public m1.tiny 70 | fi 71 | if ! openstack flavor show m1.small; then 72 | openstack flavor create --ram 2048 --disk 15 --vcpu 1 --ephemeral 1 --public m1.small 73 | fi 74 | if ! openstack flavor show m1.medium; then 75 | openstack flavor create --ram 4096 --disk 20 --vcpu 2 --ephemeral 2 --public m1.medium 76 | fi 77 | if ! openstack flavor show m1.large; then 78 | openstack flavor create --ram 8192 --disk 25 --vcpu 4 --ephemeral 5 --public m1.large 79 | fi 80 | if ! openstack flavor show m1.large.nodisk; then 81 | openstack flavor create --ram 8192 --disk 0 --vcpu 4 --public m1.large.nodisk 82 | fi 83 | if ! openstack flavor show m1.xlarge; then 84 | openstack flavor create --ram 16384 --disk 40 --vcpu 4 --ephemeral 10 --public m1.xlarge 85 | fi 86 | if ! openstack flavor show m1.xlarge.nodisk; then 87 | openstack flavor create --ram 16384 --disk 0 --vcpu 4 --public m1.xlarge.nodisk 88 | fi 89 | if ! openstack flavor show m1.large.nfv; then 90 | openstack flavor create --ram 8192 --disk 25 --vcpu 4 --ephemeral 5 --public m1.large.nfv 91 | openstack flavor set --property hw:cpu_policy=dedicated --property hw:mem_page_size=large m1.large.nfv 92 | fi 93 | if ! openstack flavor show m1.xlarge.nfv; then 94 | openstack flavor create --ram 16384 --disk 40 --vcpu 4 --ephemeral 10 --public m1.xlarge.nfv 95 | openstack flavor set --property hw:cpu_policy=dedicated --property hw:mem_page_size=large m1.xlarge.nfv 96 | fi 97 | environment: 98 | OS_CLOUD: standalone 99 | 100 | - name: Create external network # noqa no-changed-when 101 | ansible.builtin.shell: | 102 | if ! openstack network show external; then 103 | openstack network create --external --provider-physical-network external --provider-network-type flat external 104 | fi 105 | if ! openstack subnet show external-subnet; then 106 | openstack subnet create external-subnet --subnet-range "{{ external_cidr }}" \ 107 | --no-dhcp --gateway "{{ external_gateway }}" \ 108 | --allocation-pool "start={{ external_fip_pool_start }},end={{ external_fip_pool_end }}" \ 109 | --network external 110 | fi 111 | environment: 112 | OS_CLOUD: standalone 113 | when: 114 | - external_fip_pool_start is defined 115 | - external_fip_pool_end is defined 116 | - dpdk_interface is not defined 117 | 118 | - name: Create hostonly network # noqa no-changed-when 119 | ansible.builtin.shell: | 120 | if ! openstack network show hostonly; then 121 | openstack network create --project openshift --share --external --provider-physical-network hostonly --provider-network-type flat hostonly 122 | fi 123 | if ! openstack subnet show hostonly-subnet; then 124 | openstack subnet create --project openshift hostonly-subnet --subnet-range "{{ hostonly_cidr }}" \ 125 | --dhcp --gateway "{{ hostonly_gateway }}" \ 126 | --dns-nameserver "{{ network_info.dns | first }}" \ 127 | --allocation-pool "start={{ hostonly_fip_pool_start }},end={{ hostonly_fip_pool_end }}" \ 128 | --network hostonly 129 | fi 130 | if ! openstack subnet show hostonly-subnet-v6; then 131 | openstack subnet create --project openshift hostonly-subnet-v6 --subnet-range "{{ hostonly_v6_cidr }}" \ 132 | --dhcp --gateway "{{ hostonly_v6_gateway }}" \ 133 | --allocation-pool "start={{ hostonly_v6_fip_pool_start }},end={{ hostonly_v6_fip_pool_end }}" \ 134 | --network hostonly --ip-version 6 --ipv6-ra-mode dhcpv6-stateful --ipv6-address-mode dhcpv6-stateful 135 | fi 136 | environment: 137 | OS_CLOUD: standalone 138 | 139 | - name: Create hostonly-sriov network # noqa no-changed-when 140 | when: sriov_interface is defined 141 | ansible.builtin.shell: | 142 | if ! openstack network show hostonly-sriov; then 143 | openstack network create --project openshift --share --external \ 144 | --provider-physical-network hostonly-sriov --provider-network-type flat hostonly-sriov 145 | fi 146 | if ! openstack subnet show hostonly-sriov-subnet; then 147 | openstack subnet create --project openshift hostonly-sriov-subnet \ 148 | --subnet-range "{{ hostonly_sriov_cidr }}" \ 149 | --no-dhcp --gateway "{{ hostonly_sriov_gateway }}" \ 150 | --dns-nameserver "{{ network_info.dns | first }}" \ 151 | --allocation-pool "start={{ hostonly_sriov_fip_pool_start }},end={{ hostonly_sriov_fip_pool_end }}" \ 152 | --network hostonly-sriov 153 | fi 154 | environment: 155 | OS_CLOUD: standalone 156 | 157 | - name: Create basic security group which allows SSH # noqa no-changed-when 158 | ansible.builtin.shell: | 159 | if ! openstack security group show allow_ssh; then 160 | openstack security group create allow_ssh --project openshift 161 | openstack security group rule create --protocol tcp --dst-port 22 --project openshift allow_ssh 162 | fi 163 | environment: 164 | OS_CLOUD: standalone 165 | 166 | - name: Create basic security group which allows ping # noqa no-changed-when 167 | ansible.builtin.shell: | 168 | if ! openstack security group show allow_ping; then 169 | openstack security group create allow_ping --project openshift 170 | openstack security group rule create --protocol icmp --project openshift allow_ping 171 | openstack security group rule create --protocol ipv6-icmp --project openshift allow_ping 172 | fi 173 | environment: 174 | OS_CLOUD: standalone 175 | 176 | # openstack cli doesn't have manila support (no openstack share type ...)in RHEL/OSP 177 | - name: Create Manila default share type # noqa no-changed-when 178 | when: manila_enabled 179 | block: 180 | 181 | - name: Convert clouds.yaml to legacy environment variables 182 | ansible.builtin.script: files/cloud-to-env.py 183 | register: os_env_vars 184 | environment: 185 | OS_CLOUD: standalone 186 | 187 | # type-show MUST NOT have OS_SHARE_API_VERSION set 188 | # type-create MUST have OS_SHARE_API_VERSION set 189 | - name: Create Manila default share type # noqa no-changed-when 190 | ansible.builtin.shell: | 191 | if ! OS_SHARE_API_VERSION= manila type-show default; then 192 | manila type-create default false 193 | fi 194 | environment: "{{ legacy_vars | combine(extra_vars) }}" 195 | vars: 196 | legacy_vars: "{{ os_env_vars.stdout | from_json }}" 197 | extra_vars: 198 | # https://bugzilla.redhat.com/show_bug.cgi?id=1960710 199 | OS_SHARE_API_VERSION: 2.60 200 | 201 | - name: Gather the package facts 202 | ansible.builtin.package_facts: 203 | manager: auto 204 | 205 | - name: Disable snapshot support on pre-Wallaby Manila # noqa no-changed-when 206 | when: ansible_facts.packages['python3-manilaclient'][0].version is version('2.6.0', '<') 207 | ansible.builtin.shell: | 208 | manila type-key default set snapshot_support=False 209 | environment: "{{ legacy_vars | combine(extra_vars) }}" 210 | vars: 211 | legacy_vars: "{{ os_env_vars.stdout | from_json }}" 212 | extra_vars: 213 | # https://bugzilla.redhat.com/show_bug.cgi?id=1960710 214 | OS_SHARE_API_VERSION: 2.60 215 | 216 | - name: Increase default quotas for shares and snapshots # noqa no-changed-when 217 | ansible.builtin.shell: | 218 | manila quota-update --shares 150 --snapshots 150 openshift 219 | environment: "{{ legacy_vars }}" 220 | vars: 221 | legacy_vars: "{{ os_env_vars.stdout | from_json }}" 222 | 223 | - name: Read clouds.yaml 224 | ansible.builtin.slurp: 225 | src: &cloudsyamlpath /home/stack/.config/openstack/clouds.yaml 226 | register: cloudsyaml 227 | 228 | - name: Parse cloud.yaml 229 | ansible.builtin.set_fact: 230 | cloudsyaml: "{{ cloudsyaml['content'] | b64decode | from_yaml }}" 231 | 232 | - name: Extract standalone cloud config 233 | ansible.builtin.set_fact: 234 | standalone: "{{ cloudsyaml['clouds']['standalone'] }}" 235 | 236 | - name: Add shiftstack entry to clouds.yaml 237 | ansible.builtin.set_fact: 238 | cloudsyaml: "{{ cloudsyaml | combine({'clouds': {'openshift': openshift}}, recursive=true) }}" 239 | vars: 240 | openshift: 241 | auth: 242 | auth_url: "{{ standalone['auth']['auth_url'] }}" 243 | password: "{{ openshift_password }}" 244 | project_domain_name: Default 245 | project_name: openshift 246 | user_domain_name: Default 247 | username: openshift 248 | cacert: "{{ standalone['cacert'] }}" 249 | identity_api_version: "{{ standalone['identity_api_version'] }}" 250 | volume_api_version: "{{ standalone['volume_api_version'] | default('3') }}" 251 | region_name: "{{ standalone['region_name'] }}" 252 | 253 | - name: Write updated clouds.yaml 254 | ansible.builtin.copy: 255 | dest: *cloudsyamlpath 256 | content: "{{ cloudsyaml | to_nice_yaml }}" 257 | mode: '755' 258 | -------------------------------------------------------------------------------- /playbooks/prepare_host.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: root 5 | gather_facts: true 6 | vars_files: vars/defaults.yaml 7 | name: Tasks for prepare the host 8 | tasks: 9 | - name: Create the stack user 10 | ansible.builtin.user: 11 | name: stack 12 | groups: wheel 13 | 14 | - name: Configure authorized SSH keys for stack user 15 | when: (authorized_keys | length) > 0 16 | ansible.posix.authorized_key: 17 | user: stack 18 | state: present 19 | key: "{{ item }}" 20 | loop: "{{ authorized_keys }}" 21 | 22 | - name: Make sure persistent NIC names is not disabled # noqa no-changed-when 23 | ansible.builtin.shell: | 24 | if grep -q net.ifnames=0 /etc/default/grub; then 25 | sed -i 's/net.ifnames=0//g' /etc/default/grub 26 | for f in grub2 grub2-efi; do 27 | grub2-mkconfig -o $(readlink -f /etc/$f.cfg) 28 | done 29 | fi 30 | register: grub_output 31 | 32 | - name: Prepare host on RHEL system with Subscription Manager 33 | when: 34 | - ansible_facts.distribution == 'RedHat' 35 | - rhsm_enabled 36 | block: 37 | - name: Configure Red Hat Subscription Manager 38 | ansible.builtin.import_role: 39 | name: redhat-subscription 40 | - name: Install container-tools module # noqa no-changed-when 41 | ansible.builtin.shell: | 42 | dnf module disable -y container-tools:rhel8 43 | dnf module enable -y container-tools:"{{ rhsm_container_tools_version }}" 44 | when: ansible_distribution_major_version | int < 9 45 | - name: Install virt module # noqa no-changed-when 46 | ansible.builtin.shell: | 47 | dnf module disable -y virt:rhel 48 | dnf module enable -y virt:"{{ virt_release }}" 49 | when: ansible_distribution_major_version | int < 9 50 | 51 | - name: Prepare host on RHEL system with rhos-release 52 | when: 53 | - ansible_facts.distribution == 'RedHat' 54 | - not rhsm_enabled 55 | block: 56 | - name: Install rhos-release 57 | ansible.builtin.yum: 58 | state: installed 59 | name: http://download.hosts.prod.upshift.rdu2.redhat.com/rcm-guest/puddles/OpenStack/rhos-release/rhos-release-latest.noarch.rpm 60 | disable_gpg_check: true 61 | 62 | - name: Fetch the Red Hat root certificates 63 | ansible.builtin.get_url: 64 | dest: "/etc/pki/ca-trust/source/anchors/{{ item }}-IT-Root-CA.pem" 65 | url: "https://certs.corp.redhat.com/certs/{{ item }}-IT-Root-CA.pem" 66 | mode: '640' 67 | loop: 68 | - 2022 69 | register: rhca 70 | 71 | - name: Add the certificate to the local trust bundle # noqa no-changed-when no-handler 72 | ansible.builtin.shell: | 73 | update-ca-trust enable 74 | update-ca-trust extract 75 | when: rhca.changed 76 | 77 | - name: Configure rhos release and keep puddle name for "{{ rhos_release }}" # noqa no-changed-when 78 | ansible.builtin.shell: | 79 | set -o pipefail 80 | rhos-release "{{ rhos_release }}" | awk '/^# rhos-release/ { print $5 }' 81 | register: rhos_release_puddle 82 | 83 | - name: Extract puddle name from rhos-release output 84 | ansible.builtin.set_fact: 85 | puddle: "{{ rhos_release_puddle.stdout_lines.0 }}" 86 | puddle_base: "http://download.hosts.prod.upshift.rdu2.redhat.com/rcm-guest/puddles/OpenStack" 87 | 88 | - name: Download container_image_prepare.yaml for "{{ puddle }}" 89 | ansible.builtin.get_url: 90 | url: "{{ puddle_base }}/{{ rhos_release }}-RHEL-{{ ansible_facts.distribution_major_version }}/{{ puddle }}/container_image_prepare.yaml" 91 | dest: /home/stack/container_image_prepare.yaml 92 | owner: stack 93 | group: stack 94 | mode: '644' 95 | 96 | # To ensure that our CentOS users are actually using Stream. 97 | # TripleO Master only support Stream now. 98 | - name: Migrate to CentOS Stream if not done already 99 | when: 100 | - ansible_facts.distribution == 'CentOS' 101 | - ansible_facts.distribution_release != 'Stream' 102 | ansible.builtin.shell: | 103 | if ! rpm --query centos-stream-release; then 104 | dnf -y swap centos-linux-repos centos-stream-repos 105 | dnf -y distro-sync 106 | fi 107 | args: 108 | warn: false 109 | register: stream_output 110 | changed_when: (stream_output.stdout_lines | length) > 1 111 | 112 | # To get latest version of podman & dependencies we need this 113 | # version for now. 114 | - name: Ensure that container-tools 3.0 is being used # noqa no-changed-when 115 | when: 116 | - ansible_facts.distribution == 'CentOS' 117 | - ansible_facts.distribution_major_version == "8" 118 | ansible.builtin.shell: | 119 | dnf module disable -y container-tools:rhel8 120 | dnf module enable -y container-tools:3.0 121 | args: 122 | warn: false 123 | 124 | # This fixes a bogus resolv.conf entry in the CentOS cloud image. The CentOS 125 | # cloud image disables this in /etc/NetworkManager/conf.d/99-cloud-init.conf 126 | # by setting [main]/dns=none. Here we replace it with the default, which 127 | # re-enables NetworkManager's default behaviour of completely owning 128 | # resolv.conf 129 | - name: Enable NetworkManager ownership of resolv.conf 130 | when: 131 | - ansible_facts.distribution == 'CentOS' 132 | block: 133 | - name: Set main/dns=default in NetworkManager 134 | community.general.ini_file: 135 | path: /etc/NetworkManager/conf.d/99-cloud-init.conf 136 | section: main 137 | option: dns 138 | value: default 139 | mode: '644' 140 | - name: Reload NetworkManager to regenerate resolv.conf 141 | ansible.builtin.systemd: 142 | name: NetworkManager 143 | enabled: true 144 | state: reloaded 145 | 146 | - name: Prepare host on CentOS system 147 | when: 148 | - ansible_facts.distribution == 'CentOS' 149 | block: 150 | - name: Configure tripleo repositories 151 | ansible.builtin.import_role: 152 | name: tripleo.operator.tripleo_repos 153 | 154 | - name: Install dnf-utils 155 | ansible.builtin.package: 156 | name: dnf-utils 157 | state: installed 158 | 159 | - name: Upgrade all packages # noqa package-latest 160 | ansible.builtin.yum: 161 | name: '*' 162 | state: latest 163 | 164 | - name: Reboot the node when necessary 165 | when: 166 | # We don't need to reboot when these parameters are defined because 167 | # we'll reboot after the tripleo deployment anyway. We're saving one reboot. 168 | - not (sriov_interface is defined or dpdk_interface is defined or kernel_args is defined) or ((grub_output.stdout_lines | length) > 1) 169 | block: 170 | - name: Check if reboot is required # noqa no-changed-when 171 | ansible.builtin.shell: | 172 | needs-restarting -r 173 | register: needs_reboot 174 | # the commands can return non-zero codes if reboot is needed 175 | failed_when: needs_reboot.rc != 0 and needs_reboot.rc != 1 176 | - name: Reboot if we updated packages # noqa no-handler 177 | ansible.builtin.reboot: 178 | when: needs_reboot.rc == 1 or ((grub_output.stdout_lines | length) > 1) 179 | 180 | - name: Set FQDN 181 | ansible.builtin.set_fact: 182 | fqdn: "{{ hostname }}.{{ clouddomain }}" 183 | 184 | - name: Set hostname to "{{ fqdn }}" 185 | ansible.builtin.hostname: 186 | name: "{{ fqdn }}" 187 | 188 | - name: Allow 'wheel' group to have passwordless sudo 189 | ansible.builtin.lineinfile: 190 | dest: /etc/sudoers 191 | state: present 192 | regexp: '^%wheel' 193 | line: '%wheel ALL=(ALL) NOPASSWD: ALL' 194 | validate: 'visudo -cf %s' 195 | 196 | - name: Configure disks for local ephemeral storage 197 | when: 198 | - ephemeral_storage_devices|length > 0 199 | block: 200 | - name: Ensure we have lvm2 201 | ansible.builtin.package: 202 | name: lvm2 203 | state: present 204 | - name: Create VG for local ephemeral storage 205 | community.general.lvg: 206 | vg: vg_nova 207 | pvs: "{{ ephemeral_storage_devices | join(',') }}" 208 | - name: Create LV for local ephemeral storage 209 | community.general.lvol: 210 | vg: vg_nova 211 | lv: data 212 | size: 100%VG 213 | - name: Create XFS filesystem for local ephemeral storage 214 | community.general.filesystem: 215 | fstype: xfs 216 | dev: /dev/vg_nova/data 217 | - name: Create /var/lib/nova 218 | ansible.builtin.file: 219 | path: /var/lib/nova 220 | state: directory 221 | mode: '755' 222 | - name: Mount /var/lib/nova 223 | ansible.posix.mount: 224 | path: /var/lib/nova 225 | src: /dev/vg_nova/data 226 | fstype: xfs 227 | state: mounted 228 | 229 | - name: Prepare host for Ceph (loop device) 230 | when: 231 | - ceph_enabled 232 | - ceph_devices is not defined 233 | block: 234 | - name: Make sure we have losetup installed/latest 235 | ansible.builtin.package: 236 | name: 237 | - util-linux 238 | - lvm2 239 | state: present 240 | - name: Create a backing file for ceph 241 | ansible.builtin.command: /usr/bin/fallocate -l {{ ceph_loop_device_size }}G /var/lib/ceph-osd.img 242 | args: 243 | creates: /var/lib/ceph-osd.img 244 | - name: Create /etc/systemd/system/ceph-osd-losetup.service 245 | ansible.builtin.copy: 246 | dest: /etc/systemd/system/ceph-osd-losetup.service 247 | mode: '755' 248 | content: | 249 | [Unit] 250 | Description=Ceph OSD losetup 251 | After=syslog.target 252 | [Service] 253 | Type=oneshot 254 | ExecStart=/bin/bash -c '/sbin/losetup /dev/loop1 || /sbin/losetup --direct-io=on /dev/loop1 /var/lib/ceph-osd.img' 255 | ExecStop=/sbin/losetup -d /dev/loop1 256 | RemainAfterExit=yes 257 | [Install] 258 | WantedBy=multi-user.target 259 | register: create_losetup_service 260 | - name: Enable ceph-osd-losetup.service 261 | ansible.builtin.systemd: 262 | name: ceph-osd-losetup.service 263 | enabled: true 264 | state: "{{ create_losetup_service.changed | ternary('restarted', 'started') }}" 265 | daemon_reload: "{{ create_losetup_service.changed }}" 266 | - name: Create volume group for ceph 267 | community.general.lvg: 268 | vg: vg_ceph 269 | pvs: /dev/loop1 270 | - name: Create ceph data LV 271 | community.general.lvol: 272 | vg: vg_ceph 273 | lv: data 274 | size: 96%VG 275 | - name: Create ceph db LV 276 | community.general.lvol: 277 | vg: vg_ceph 278 | lv: db 279 | size: 4%VG 280 | 281 | - name: Prepare host for Ceph (disk device) 282 | when: 283 | - ceph_enabled 284 | - ceph_devices is defined 285 | - ceph_devices is not true 286 | - (ceph_devices | length) > 0 287 | block: 288 | - name: Wipe filesystem from disk # noqa no-changed-when 289 | ansible.builtin.command: wipefs -a "{{ item }}" 290 | loop: "{{ ceph_devices }}" 291 | - name: Expose Ceph devices to LVM 292 | when: 293 | - ceph_devices_to_lvm 294 | block: 295 | - name: Ensure we have lvm2 296 | ansible.builtin.package: 297 | name: lvm2 298 | state: present 299 | - name: Create VG for ceph devices 300 | community.general.lvg: 301 | vg: vg_ceph 302 | pvs: "{{ ceph_devices | join(',') }}" 303 | - name: Create LV for ceph devices 304 | community.general.lvol: 305 | vg: vg_ceph 306 | lv: data 307 | size: 100%VG 308 | 309 | - name: Prepare kernel and reboot 310 | when: 311 | - kernel_args is defined 312 | block: 313 | - name: Install driverctl rpm # noqa no-changed-when 314 | ansible.builtin.package: 315 | name: 316 | - driverctl 317 | state: present 318 | - name: Configure tuned before reboot # noqa no-changed-when 319 | ansible.builtin.include_role: 320 | name: tuned 321 | vars: 322 | tuned_profile: cpu-partitioning 323 | - name: Configure kernel args and reboot # noqa no-changed-when 324 | ansible.builtin.include_role: 325 | name: tripleo_kernel 326 | tasks_from: kernelargs.yml 327 | vars: 328 | tripleo_kernel_args: "{{ kernel_args | mandatory }}" 329 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dev-install 2 | 3 | `dev-install` installs [TripleO standalone](https://docs.openstack.org/project-deploy-guide/tripleo-docs/latest/deployment/standalone.html) on a remote system for development use. 4 | 5 | ## Host configuration 6 | 7 | `dev-install` requires that: 8 | 9 | * An appropriate OS has already been installed 10 | * EPEL repositories aren't deployed, they aren't compatible with OpenStack repositories 11 | * The machine running `dev-install` can SSH to the standalone host as either root or a user with passwordless sudo access 12 | * This machine has Ansible installed, and some dependencies like `python3-netaddr`. 13 | 14 | You need to deploy the right RHEL version depending on which OSP version you want: 15 | 16 | | OSP version | RHEL Version | 17 | |--------------|--------------| 18 | | 16.2 | 8.4 | 19 | | 17.1* | 9.2 | 20 | 21 | > Current default. 22 | 23 | There is no need to do any other configuration prior to running `dev-install`. 24 | When deploying on TripleO from upstream, you need to deploy on CentOS Stream. If CentOS is not Stream, dev-install will migrate it. 25 | 26 | ## Local pre-requisites 27 | 28 | `dev-install` requires up to date versions of `ansible` and `make`, both of which must be installed manually before invoking `dev-install`. 29 | 30 | If installing OSP 16.2 with official RHEL 8.4 cloud images, it is required that the `cloud-init` service be disabled before deployment as per [THIS](https://review.opendev.org/c/openstack/tripleo-heat-templates/+/764933) 31 | 32 | At present the deployment depends on a valid DHCP source for the external interface (`br-ex`) as per [THIS](https://github.com/shiftstack/dev-install/blob/main/playbooks/templates/dev-install_net_config.yaml.j2#L9) 33 | 34 | All other requirements should be configured automatically by Ansible. Note that `dev-install` does require root access (or passwordless sudo) on the machine it is invoked from to install certificate management tools (simpleca) in addition to the remote host. 35 | 36 | ## Defining registry 37 | 38 | Recently, there were changed way for accessing RedHat registry. Now it's mandatory to provide credentials to `local-override.yaml` file in a form of a list: 39 | 40 | ```yaml 41 | registers: 42 | - name: registry1.url 43 | username: joe 44 | password: secret 45 | - name: registry2.url 46 | username: alice 47 | password: supersecret 48 | ``` 49 | 50 | RedHat registry, is expected to be the first one. 51 | 52 | ## Running dev-install 53 | 54 | `dev-install` is invoked using its `Makefile`. The simplest invocation is: 55 | 56 | ```console 57 | make config host= 58 | make osp_full 59 | ``` 60 | 61 | `make config` initialises two local state files: 62 | 63 | * `inventory` - this is an Ansible inventory file, initialised such that `standalone` is an alias for your target host. 64 | * `local-overrides.yaml` - this is an Ansible vars file containing configuration which overrides the defaults in `playbooks/vars/defaults.yaml`. 65 | 66 | Both of these files can be safely modified. 67 | 68 | `make osp_full` performs the actual installation. On an example system with 12 cores and 192GB RAM and running in a Red Hat data centre this takes approximately 65 minutes to execute. 69 | 70 | If you deal with multiple OpenStack clouds and want to maintain a single local-overrides per cloud, you can create `local-overrides-.yaml` 71 | and then use it when deploying with `make osp_full overrides=local-overrides-.yaml` 72 | 73 | ## Accessing OpenStack from your workstation 74 | 75 | By default, `dev-install` configures OpenStack to use the default public IP of the host. 76 | To access this you just need a correct `clouds.yaml`, which `dev-install` configures with: 77 | 78 | ```console 79 | make local_os_client 80 | ``` 81 | 82 | This will configure your local `clouds.yaml` with two entries: 83 | 84 | * `standalone` - The admin user 85 | * `standalone_openshift` - The appropriately configured non-admin `openshift` user 86 | 87 | You can change the name of these entries by editing `local-overrides.yaml` and setting `local_cloudname` to something else. 88 | 89 | ## Validating the installation 90 | 91 | `dev-install` provides an additional playbook to validate the fresh deployment. This can be run with: 92 | 93 | ```console 94 | make prepare_stack_testconfig 95 | ``` 96 | 97 | This can be used to configure some helpful defaults for validating your cluster, namely: 98 | 99 | - Configure SSH access 100 | - Configure routers and security groups to allow external network connectivity 101 | for created guests 102 | - Upload a Cirros image 103 | 104 | ## Network configuration 105 | 106 | `dev-install` will create a new OVS bridge called `br-ex` and move the host's external interface on to that bridge. 107 | This bridge is used to provide the `external` provider network if `external_fip_pool_start` and `external_fip_pool_end` are defined in `local-overrides.yaml`. 108 | 109 | In addition it will create OVS bridges called `br-ctlplane` and `br-hostonly`. The former is used internally by OSP. The latter is a second provider network which is only routable from the host. 110 | 111 | Note that we don't enable DHCP on provider networks by default, and it is not recommended to enable DHCP on the external network at all. To enable DHCP on the `hostonly` network after installation, run: 112 | 113 | ```console 114 | OS_CLOUD=standalone openstack subnet set --dhcp hostonly-subnet 115 | ``` 116 | 117 | `make local_os_client` will write a [sshuttle](https://github.com/sshuttle/sshuttle) script to `scripts/sshuttle-standalone.sh` which will route to the `hostonly` provider network over ssh. 118 | 119 | ## Configuration 120 | 121 | `dev-install` is configured by overriding variables in `local-overrides.yaml`. 122 | See the [default variable definitions](https://github.com/shiftstack/dev-install/blob/master/playbooks/vars/defaults.yaml) for what can be overridden. 123 | 124 | ## Sizing 125 | 126 | When idle, a standalone deployment uses approximately: 127 | 128 | * 16GB RAM 129 | * 15G on `/` 130 | * 3.5G on `/home` 131 | * 3.6G on `/var/lib/cinder` 132 | * 3.6G on `/var/lib/nova` 133 | 134 | There is no need to mount `/var/lib/cinder` and `/var/lib/nova` separately if `/` is large enough for your workload. 135 | 136 | ## Advanced features 137 | 138 | ### NFV enablement 139 | 140 | This section contains configuration procedures for single root input/output virtualization (SR-IOV) for network functions virtualization infrastructure (NFVi) in your Standalone OpenStack deployment. 141 | Unfortunately, most of these parameters don't have default values nor can they be automatically calculated in a Standalone-type environment. 142 | 143 | #### SR-IOV Variables 144 | 145 | To understand how the SR-IOV configuration works, please have a look at this [upstream guide](https://docs.openstack.org/neutron/latest/admin/config-sriov.html). 146 | 147 | | Name | Default Value | Description | 148 | |-------------------|---------------------|----------------------| 149 | | `sriov_services` | `['OS::TripleO::Services::NeutronSriovAgent', 'OS::TripleO::Services::BootParams']` | List of TripleO services to add to the default Standalone role | 150 | | `sriov_interface` | `[undefined]` | Name of the SR-IOV capable interface. Must be enabled in BIOS (e.g. `ens1f0`) | 151 | | `sriov_nic_numvfs` | `[undefined]` | Number of Virtual Functions that the NIC can handle. | 152 | | `sriov_nova_pci_passthrough` | `[undefined]` | List of PCI Passthrough allowlist parameters. [Guidelines](https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/16.1/html/configuring_the_compute_service_for_instance_creation/configuring-pci-passthrough#guidelines-for-configuring-novapcipassthrough-osp) to configure it. | 153 | 154 | Note: when SR-IOV is enabled, a dedicated provider network will be created and bound to the SR-IOV interface. 155 | 156 | #### Kernel Variables 157 | 158 | It is possible to configure the Kernel to boot with specific arguments: 159 | 160 | | Name | Default Value | Description | 161 | |-------------------|---------------------|----------------------| 162 | | `kernel_services` | `['TripleO::Services::BootParams']` | List of TripleO services to add to the default Standalone role | 163 | | `kernel_args` | `[undefined]` | Kernel arguments to configure when booting the machine. | 164 | 165 | #### DPDK Variables 166 | 167 | It is possible to configure the deployment to be ready for DPDK: 168 | 169 | | Name | Default Value | Description | 170 | |-------------------|---------------------|----------------------| 171 | | `dpdk_services` | `['OS::TripleO::Services::ComputeNeutronOvsDpdk']` | List of TripleO services to add to the default Standalone role | 172 | | `dpdk_interface` | `[undefined]` | Name of the DPDK capable interface. Must be enabled in BIOS. e.g. `ens1f0` | 173 | | `tuned_isolated_cores` | `[undefined]` | List of logical CPU ids which need to be isolated from the host processes. This input is provided to the tuned profile CPU-partitioning to configure systemd and repin interrupts (IRQ repinning). | 174 | 175 | When deploying DPDK, it is suggested to configure these options: 176 | 177 | ```yaml 178 | extra_heat_params: 179 | # A list or range of host CPU cores to which processes for pinned instance 180 | # CPUs (PCPUs) can be scheduled: 181 | NovaComputeCpuDedicatedSet: ['6-47'] 182 | # Reserved RAM for host processes: 183 | NovaReservedHostMemory: 4096 184 | # Determine the host CPUs that unpinned instances can be scheduled to: 185 | NovaComputeCpuSharedSet: [0,1,2,3] 186 | # Sets the amount of hugepage memory to assign per NUMA node: 187 | OvsDpdkSocketMemory: "2048,2048" 188 | # A list or range of CPU cores for PMD threads to be pinned to: 189 | OvsPmdCoreList: "4,5" 190 | ``` 191 | 192 | #### SSL for public endpoints 193 | 194 | This sections contains configuration procedures for enabling SSL on OpenStack public endpoints. 195 | 196 | | Name | Default Value | Description | 197 | |-------------------|---------------------|----------------------| 198 | | `ssl_enabled` | `false` | Whether or not we enable SSL for public endpoints | 199 | | `ssl_ca_cert` | `[undefined]` | CA certificate. If undefined, a self-signed will be generated and deployed | 200 | | `ssl_ca_key` | `[undefined]` | CA key. If undefined, it will be generated and used to sign the SSL certificate | 201 | | `ssl_key` | `[undefined]` | SSL Key. If undefined, it will be generated and deployed | 202 | | `ssl_cert` | `[undefined]` | SSL certificate. If undefined, a self-signed will be generated and deployed | 203 | | `ssl_ca_cert_path` | `/etc/pki/ca-trust/source/anchors/simpleca.crt` | Path to the CA certificate | 204 | | `update_local_pki` | `false` | Whether or not we want to update the local PKI with the CA certificate | 205 | 206 | #### Multi-node deployments 207 | 208 | It is possible to deploy Edge-style environments, where multiple AZ are configured. 209 | 210 | ##### Deploy the Central site 211 | 212 | Deploy a regular cloud with `dev-install`, and make sure you set these parameters: 213 | 214 | * `dcn_az`: has to be `central`. 215 | * `tunnel_remote_ips`: list of known public IPs of the AZ nodes. 216 | 217 | Once this is done, you need to collect the content from `/home/stack/exported-data` into a local directory on the host where `dev-install` is executed. 218 | 219 | ##### Deploy the "AZ" sites 220 | 221 | Before deploying OSP, you need to `scp` the content from `exported-data` into the remote hosts into `/opt/exported-data`. 222 | Once this is done, you can deploy the AZ sites with a regular config for `dev-install`, except that you'll need to set these parameters: 223 | 224 | * `dcn_az`: must contains `az` in the string (e.g. `az0`, `az1`) 225 | * `local_ip`: choose an available IP in the control plane subnet (e.g. `192.168.24.10`) 226 | * `control_plane_ip`: same as for `local_ip`, pick one that is available (e.g. `192.168.24.11`) 227 | * `hostonly_gateway`: if using provider networks, you'll need to select an available IP (e.g. `192.168.25.2`) 228 | * `tunnel_remote_ips`: the list of known public IPs that will be used to establish the VXLAN tunnels 229 | * `hostname`: you must make sure both central and AZ doesn't use the default hostname (`standalone`), so set it at least on the compute (e.g. `compute1`) 230 | * `octavia_enabled`: set to `false` 231 | 232 | Notes: 233 | 234 | * Control plane IPs (`192.168.24.x`) are arbitrary, if in doubt just use the example ones. 235 | * The control plane bridges will be connected thanks to VXLAN tunnels, which is why we need to select control plane IP for AZ nodes that were not taken on the Central site. 236 | * If you deploy the clouds in OpenStack, you need to make sure that the security groups allow VXLAN (`udp/4789`). 237 | * If the public IPs aren't predictable, you'll need to manually change the MTU on the `br-ctlplane` and `br-hostonly` on the central 238 | site and the AZ sites where needed. You can do it by editing the `os-net-config` configuration file and run `os-net-config` to apply 239 | it. 240 | 241 | After the installation you can "join" AZs to just have a regular multi-node cloud. E.g.: 242 | 243 | ```console 244 | openstack aggregate remove host az0 compute1.shiftstack 245 | openstack aggregate add host central compute1.shiftstack 246 | ``` 247 | 248 | Then if you're using OVN (you probably are) you got to execute this on compute nodes: 249 | 250 | ```console 251 | ovs-vsctl set Open_vSwitch . external-ids:ovn-cms-options="enable-chassis-as-gw,availability-zones=central" 252 | ``` 253 | 254 | #### Post Deployment Stack Updates 255 | 256 | It is possible to perform stack updates on an ephemeral standalone stack. 257 | 258 | Copying the generated `tripleo_deploy.sh` in your deployment users folder (e.g. `/home/stack/tripleo_deploy.sh`) to `tripleo_update.sh` and add the parameter `--force-stack-update`. 259 | This will allow you to modify the stack configuration without needing to redeploy the entire cloud which can save you considerable time. 260 | 261 | #### Post install script 262 | 263 | It is possible to run any script in post-install with `post_install` parameter: 264 | 265 | ```yaml 266 | post_install: | 267 | export OS_CLOUD=standalone 268 | openstack flavor set --property hw:mem_page_size=large m1.smal 269 | ``` 270 | 271 | And then run `make post_install`. 272 | 273 | ## Troubleshooting 274 | 275 | If installation fails, examine the Ansible logs for more information. 276 | Failures will usually occur early in the process or during the `tripleo_deploy` stage. If the latter, you can look at the logs in `/home/stack/standalone_deploy.log`. 277 | Once the issue has been addressed, you can resume the deployment by stopping `heat` and running the `openstack tripleo deploy` command again via the `tripleo_deploy.sh` script: 278 | 279 | ```console 280 | sudo pkill -9 heat-all 281 | ./triple_deploy.sh 282 | ``` 283 | -------------------------------------------------------------------------------- /playbooks/install_stack.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: standalone 3 | become: true 4 | become_user: stack 5 | gather_facts: false 6 | vars_files: vars/defaults.yaml 7 | name: Deploy OpenStack 8 | roles: 9 | - network_info 10 | tasks: 11 | - name: Get minimum ansible facts 12 | ansible.builtin.setup: 13 | gather_subset: min 14 | 15 | - name: Initialise service environment list from user provided services 16 | ansible.builtin.set_fact: 17 | service_envs: "{{ enabled_services }}" 18 | 19 | - name: Add external network VIP service 20 | ansible.builtin.set_fact: 21 | service_envs: "{{ service_envs | union(vip_env) }}" 22 | vars: 23 | vip_env: 24 | - /usr/share/openstack-tripleo-heat-templates/environments/external-network-vip.yaml 25 | 26 | # OSP16 doesn't have HA enabled by default for all service (HAproxy). 27 | # While this is being fixed, we'll force it here. 28 | - name: Enable HA by default 29 | block: 30 | - name: Add HA services 31 | ansible.builtin.set_fact: 32 | service_envs: "{{ service_envs | union(ha_env) }}" 33 | vars: 34 | ha_env: 35 | - /usr/share/openstack-tripleo-heat-templates/environments/docker-ha.yaml 36 | 37 | - name: Enable OVN DVR HA by default when deploying DCN 38 | when: 39 | - dcn_az is defined 40 | - ovn_enabled 41 | block: 42 | - name: Add OVN DVR HA services 43 | ansible.builtin.set_fact: 44 | service_envs: "{{ service_envs | union(ovn_dvr_ha_env) }}" 45 | vars: 46 | ovn_dvr_ha_env: 47 | - /usr/share/openstack-tripleo-heat-templates/environments/services/neutron-ovn-dvr-ha.yaml 48 | 49 | - name: Enable exported environments from central site when deploying DCN 50 | when: 51 | - dcn_az is defined 52 | - dcn_az != "central" 53 | block: 54 | - name: Add DCN environments 55 | ansible.builtin.set_fact: 56 | service_envs: "{{ service_envs | union(dcn_env) }}" 57 | vars: 58 | dcn_env: 59 | - /opt/exported-data/passwords.yaml 60 | - /opt/exported-data/oslo.yaml 61 | - /opt/exported-data/endpoint-map.json 62 | - /opt/exported-data/extra-host-file-entries.json 63 | - /opt/exported-data/all-nodes-extra-map-data.json 64 | 65 | - name: Enable SSL 66 | when: ssl_enabled 67 | block: 68 | - name: Add SSL service 69 | ansible.builtin.set_fact: 70 | service_envs: "{{ service_envs | union(ssl_env) }}" 71 | vars: 72 | ssl_env: 73 | - /usr/share/openstack-tripleo-heat-templates/environments/ssl/tls-endpoints-public-ip.yaml 74 | - /usr/share/openstack-tripleo-heat-templates/environments/ssl/enable-tls.yaml 75 | - /usr/share/openstack-tripleo-heat-templates/environments/ssl/inject-trust-anchor.yaml 76 | 77 | - name: Generate SSL self-signed certificate on localhost 78 | when: ssl_enabled 79 | become: false 80 | # We run this block on localhost because we don't want to put the CA key on the remote 81 | # server, which could lead to security problems. 82 | delegate_to: localhost 83 | block: 84 | - name: Create temporary directory for SSL files 85 | ansible.builtin.tempfile: 86 | state: directory 87 | suffix: dev-install-ssl 88 | register: ssl_dir 89 | - name: Generate SSL self-signed certificate 90 | ansible.builtin.include_role: 91 | name: simpleca 92 | vars: 93 | cert_user: standalone 94 | ca_dir: "{{ ssl_dir.path }}/ssl/ca" 95 | cert_dir: "{{ ssl_dir.path }}/ssl" 96 | cert_name: standalone 97 | 98 | - name: Prepare the host for SSL 99 | when: ssl_enabled 100 | no_log: true 101 | block: 102 | - name: Read and clean SSL files 103 | become: false 104 | delegate_to: localhost 105 | block: 106 | - name: Read SSL certificate 107 | ansible.builtin.slurp: 108 | src: "{{ ssl_dir.path }}/ssl/standalone.crt" 109 | register: ssl_cert_output 110 | when: ssl_cert is not defined 111 | - name: Read SSL key 112 | ansible.builtin.slurp: 113 | src: "{{ ssl_dir.path }}/ssl/standalone.key" 114 | register: ssl_key_output 115 | when: ssl_key is not defined 116 | - name: Read CA certificate 117 | ansible.builtin.slurp: 118 | src: "{{ ssl_dir.path }}/ssl/ca/simpleca.crt" 119 | register: ssl_ca_cert_output 120 | when: ssl_ca_cert is not defined 121 | # At this point the files should not be useful, so we can 122 | # clear them to avoid any leak on the host where Ansible 123 | # is run. 124 | - name: Remove temporary directory for SSL files 125 | ansible.builtin.file: 126 | state: absent 127 | path: "{{ ssl_dir.path }}" 128 | - name: Set fact for SSL cert 129 | when: ssl_cert is not defined 130 | ansible.builtin.set_fact: 131 | ssl_cert: "{{ ssl_cert_output['content'] | b64decode }}" 132 | - name: Set fact for SSL key 133 | when: ssl_key is not defined 134 | ansible.builtin.set_fact: 135 | ssl_key: "{{ ssl_key_output['content'] | b64decode }}" 136 | - name: Set fact for CA cert 137 | when: ssl_ca_cert is not defined 138 | ansible.builtin.set_fact: 139 | ssl_ca_cert: "{{ ssl_ca_cert_output['content'] | b64decode }}" 140 | - name: Copy CA cert into PKI 141 | become: true 142 | become_user: root 143 | ansible.builtin.copy: 144 | dest: "{{ ssl_ca_cert_path }}" 145 | content: "{{ ssl_ca_cert }}" 146 | mode: '444' 147 | owner: root 148 | group: root 149 | - name: Update CA trust # noqa no-changed-when 150 | become: true 151 | become_user: root 152 | ansible.builtin.command: update-ca-trust extract 153 | 154 | - name: Login into registries 155 | become: true 156 | become_user: root 157 | when: 158 | - registers is defined 159 | - (registers | length) > 0 160 | block: 161 | - name: Login to registry 162 | containers.podman.podman_login: 163 | username: "{{ item.username | ansible.builtin.mandatory }}" 164 | password: "{{ item.password | ansible.builtin.mandatory }}" 165 | registry: "{{ item.name }}" 166 | loop: "{{ registers }}" 167 | 168 | - name: Install the tripleo client 169 | ansible.builtin.yum: 170 | name: python3-tripleoclient 171 | become: true 172 | become_user: root 173 | 174 | - name: Prepare the deployment for Ceph 175 | when: ceph_enabled 176 | block: 177 | - name: Check if ceph-adm can be used to deploy Ceph 178 | ansible.builtin.stat: 179 | path: /usr/share/openstack-tripleo-heat-templates/environments/cephadm 180 | register: st_ceph 181 | - name: Create ceph_adm_enabled fact 182 | ansible.builtin.set_fact: 183 | ceph_adm_enabled: "{{ st_ceph.stat.isdir is defined and st_ceph.stat.isdir }}" 184 | - name: Show a message when ceph_devices is used but empty 185 | ansible.builtin.debug: 186 | msg: > 187 | ceph_devices contains a list of disks but cephadm is going to use all available SSD/NVME disks. 188 | Set the param to true to skip this message or remove it if you don't have available SSD/NVME disks. 189 | when: 190 | - ceph_adm_enabled 191 | - ceph_devices is defined 192 | - ceph_devices is not true 193 | - (ceph_devices | length) > 0 194 | - name: Create ceph facts 195 | ansible.builtin.set_fact: 196 | ceph_env_base: "{{ ceph_adm_enabled | ternary('cephadm', 'ceph-ansible') }}" 197 | ceph_env_name: "{{ ceph_adm_enabled | ternary('cephadm-rbd-only', 'ceph-ansible') }}" 198 | - name: "Install ceph package" 199 | ansible.builtin.yum: 200 | name: 201 | - "{{ ceph_env_base }}" 202 | become: true 203 | become_user: root 204 | 205 | - name: Set fact for dev-install_net_config template 206 | ansible.builtin.set_fact: 207 | net_config_template: "{{ dpdk_interface is defined | ternary('dev-install_net_config_dpdk.yaml.j2', 'dev-install_net_config.yaml.j2') }}" 208 | 209 | - name: Create dev-install_net_config.yaml 210 | ansible.builtin.template: 211 | mode: '644' 212 | src: "{{ net_config_template }}" 213 | dest: "{{ ansible_env.HOME }}/dev-install_net_config.yaml" 214 | 215 | - name: Run os-net-config # noqa no-changed-when 216 | ansible.builtin.command: "os-net-config --exit-on-validation-errors -d -c {{ ansible_env.HOME }}/dev-install_net_config.yaml" 217 | become: true 218 | become_user: root 219 | 220 | - name: Read dev-install_net_config.yaml 221 | ansible.builtin.slurp: 222 | src: "{{ ansible_env.HOME }}/dev-install_net_config.yaml" 223 | register: net_config 224 | 225 | - name: Create net_config_json fact 226 | ansible.builtin.set_fact: 227 | net_config_json: "{{ net_config['content'] | b64decode | from_yaml }}" 228 | 229 | - name: Set fact for SR-IOV services overrides 230 | ansible.builtin.set_fact: 231 | sriov_services_fact: "{{ sriov_interface | default(None) | ternary(sriov_services, []) }}" 232 | 233 | - name: Set fact for DPDK services overrides 234 | ansible.builtin.set_fact: 235 | dpdk_services_fact: "{{ dpdk_interface | default(None) | ternary(dpdk_services, []) }}" 236 | 237 | - name: Set fact for Kernel services overrides 238 | ansible.builtin.set_fact: 239 | kernel_services_fact: "{{ kernel_args | default(None) | ternary(kernel_services, []) }}" 240 | 241 | - name: Set fact for Manila services overrides 242 | ansible.builtin.set_fact: 243 | manila_services_fact: "{{ manila_enabled | ternary(manila_services, []) }}" 244 | 245 | - name: Set fact for DCN services overrides 246 | ansible.builtin.set_fact: 247 | dcn_services_fact: "{{ dcn_az | default(None) | ternary(dcn_services, []) }}" 248 | 249 | - name: Read the TripleO role 250 | ansible.builtin.slurp: 251 | src: "{{ standalone_role }}" 252 | register: role_yaml 253 | 254 | - name: Parse the role data 255 | ansible.builtin.set_fact: 256 | role_data: "{{ role_yaml['content'] | b64decode | from_yaml }}" 257 | 258 | - name: Set fact for the new role data 259 | ansible.builtin.set_fact: 260 | new_role_data: "{{ role_data }}" 261 | 262 | - name: Set the fact for overrides services 263 | ansible.builtin.set_fact: 264 | role_data: > 265 | {% set _ = new_role_data.0.__setitem__('ServicesDefault', new_role_data.0.ServicesDefault | 266 | union(sriov_services_fact) | union(dpdk_services_fact) | union(kernel_services_fact) | union(manila_services_fact) | 267 | union(dcn_services_fact) | union(standalone_role_overrides)) %} 268 | {{ new_role_data }} 269 | 270 | - name: Create the new role file 271 | ansible.builtin.copy: 272 | dest: "{{ ansible_env.HOME }}/tripleo_standalone_role.yaml" 273 | content: "{{ role_data }}" 274 | mode: '644' 275 | 276 | - name: Configure manila 277 | when: manila_enabled 278 | block: 279 | - name: Add manila services 280 | ansible.builtin.set_fact: 281 | service_envs: "{{ service_envs | union(manila_env) }}" 282 | vars: 283 | manila_env: 284 | - "/usr/share/openstack-tripleo-heat-templates/environments/{{ ceph_env_base }}/ceph-mds.yaml" 285 | - /usr/share/openstack-tripleo-heat-templates/environments/manila-cephfsganesha-config.yaml 286 | 287 | - name: Ensure ceph is enabled 288 | ansible.builtin.set_fact: 289 | ceph_enabled: true 290 | 291 | - name: Set fact for neutron_bridge_mappings 292 | when: 293 | - neutron_bridge_mappings is not defined 294 | block: 295 | - name: Set fact for base_bridge_mappings when DPDK is disabled 296 | ansible.builtin.set_fact: 297 | base_bridge_mappings: "external:br-ex,hostonly:br-hostonly" 298 | when: 299 | - dpdk_interface is not defined 300 | - name: Set fact for base_bridge_mappings when DPDK is enabled 301 | ansible.builtin.set_fact: 302 | base_bridge_mappings: "hostonly:br-hostonly" 303 | when: 304 | - dpdk_interface is defined 305 | - name: Construct fact for neutron_bridge_mappings 306 | ansible.builtin.set_fact: 307 | neutron_bridge_mappings: "{{ base_bridge_mappings }}" 308 | 309 | - name: Create standalone_parameters.yaml 310 | no_log: true 311 | ansible.builtin.template: 312 | mode: '644' 313 | src: standalone_parameters.yaml.j2 314 | dest: "{{ ansible_env.HOME }}/standalone_parameters.yaml" 315 | 316 | - name: Enable Octavia 317 | when: octavia_enabled 318 | block: 319 | # The Amphora image is broken for OSP17, see: 320 | # https://review.rdoproject.org/r/32023 321 | # Until then this is fine (tested) to use the latest 322 | # image from RDO: 323 | - name: Download the latest Amphora image for Octavia 324 | ansible.builtin.get_url: 325 | url: https://tarballs.opendev.org/openstack/octavia/test-images/test-only-amphora-x64-haproxy-centos-9-stream.qcow2 326 | dest: "{{ ansible_env.HOME }}/amphora.qcow2" 327 | mode: '644' 328 | 329 | - name: Generate a keypair for Octavia Amphora (needed by TripleO) 330 | ansible.builtin.shell: | 331 | if [ ! -f "{{ ansible_env.HOME }}/octavia" ]; then 332 | ssh-keygen -b 2048 -t rsa -f "{{ ansible_env.HOME }}/octavia" -q -N "" 333 | fi 334 | args: 335 | creates: "{{ ansible_env.HOME }}/octavia" 336 | 337 | - name: Add octavia to enabled services 338 | ansible.builtin.set_fact: 339 | service_envs: "{{ service_envs | union(octavia_env) }}" 340 | vars: 341 | octavia_env: 342 | - /usr/share/openstack-tripleo-heat-templates/environments/services/octavia.yaml 343 | 344 | - name: Enable Barbican 345 | when: barbican_enabled 346 | block: 347 | - name: Add barbican to enabled services 348 | ansible.builtin.set_fact: 349 | service_envs: "{{ service_envs | union(barbican_env) }}" 350 | vars: 351 | barbican_env: 352 | - /usr/share/openstack-tripleo-heat-templates/environments/services/barbican.yaml 353 | - /usr/share/openstack-tripleo-heat-templates/environments/barbican-backend-simple-crypto.yaml 354 | 355 | - name: Generate container_image_prepare.yaml if not using rhos-release # noqa no-changed-when 356 | when: 357 | - cip_config is not defined 358 | - ansible_facts.distribution == 'RedHat' 359 | - rhsm_enabled 360 | ansible.builtin.import_role: 361 | name: tripleo.operator.tripleo_container_image_prepare_default 362 | vars: 363 | tripleo_container_image_prepare_default_debug: true 364 | tripleo_container_image_prepare_default_output_env_file: /home/stack/containers-prepare-parameters.yaml 365 | 366 | # On RHEL/OSP if cip_config is not provided, we download it from latest puddle 367 | - name: Set cip_config from downloaded container_image_prepare.yaml 368 | when: 369 | - cip_config is not defined 370 | - ansible_facts.distribution == 'RedHat' 371 | - not rhsm_enabled 372 | block: 373 | - name: Read container_image_prepare.yaml 374 | ansible.builtin.slurp: 375 | src: /home/stack/container_image_prepare.yaml 376 | register: cip_yaml 377 | - name: Extract container image parameters from downloaded container_image_prepare.yaml 378 | ansible.builtin.set_fact: 379 | cip_raw: "{{ (cip_yaml.content | b64decode | from_yaml)['container-image-prepare'] | dict2items }}" 380 | - name: Set cip_config from downloaded container_image_prepare.yaml 381 | ansible.builtin.set_fact: 382 | cip_config: "{{ [{'set': dict(keys | zip(values))}] }}" 383 | vars: 384 | # container_image_prepare.yaml downloaded from the puddle contains some 385 | # keys with invalid names, e.g. 'ceph-namespace' instead of 386 | # 'ceph_namespace'. We rewrite them. 387 | keys: "{{ cip_raw | map(attribute='key') | map('regex_replace', '-', '_') | list }}" 388 | values: "{{ cip_raw | map(attribute='value') | list }}" 389 | 390 | - name: Create containers-prepare-parameters.yaml if cip_config is defined 391 | when: cip_config is defined 392 | ansible.builtin.copy: 393 | dest: "{{ ansible_env.HOME }}/containers-prepare-parameters.yaml" 394 | content: "{{ cip_content | to_nice_yaml }}" 395 | owner: stack 396 | mode: '644' 397 | vars: 398 | cip_content: 399 | parameter_defaults: 400 | ContainerImagePrepare: "{{ cip_config }}" 401 | 402 | - name: Download containers-prepare-parameters.yaml from upstream master if cip_config is not defined on CentOS 403 | when: 404 | - cip_config is not defined 405 | - ansible_facts.distribution == 'CentOS' 406 | ansible.builtin.get_url: 407 | dest: "{{ ansible_env.HOME }}/containers-prepare-parameters.yaml" 408 | url: "https://opendev.org/openstack/tripleo-common/raw/branch/master/container-images/container_image_prepare_defaults.yaml" 409 | owner: stack 410 | mode: '644' 411 | 412 | - name: Install tuned cpu partionioning profile 413 | ansible.builtin.yum: 414 | name: 415 | - tuned 416 | - tuned-profiles-cpu-partitioning 417 | become: true 418 | become_user: root 419 | 420 | - name: Add sriov-ovn to enabled services 421 | ansible.builtin.set_fact: 422 | service_envs: "{{ service_envs | union(sriov_env) }}" 423 | vars: 424 | sriov_env: 425 | - /usr/share/openstack-tripleo-heat-templates/environments/services/neutron-ovn-sriov.yaml 426 | when: 427 | - sriov_interface is defined 428 | - ovn_enabled 429 | 430 | - name: Add sriov-ovs to enabled services 431 | ansible.builtin.set_fact: 432 | service_envs: "{{ service_envs | union(sriov_env) }}" 433 | vars: 434 | sriov_env: 435 | - /usr/share/openstack-tripleo-heat-templates/environments/services/neutron-ovs.yaml 436 | - /usr/share/openstack-tripleo-heat-templates/environments/services/neutron-sriov.yaml 437 | when: 438 | - sriov_interface is defined 439 | - not ovn_enabled 440 | 441 | - name: Add dpdk-ovn to enabled services 442 | ansible.builtin.set_fact: 443 | service_envs: "{{ service_envs | union(dpdk_env) }}" 444 | vars: 445 | dpdk_env: 446 | - /usr/share/openstack-tripleo-heat-templates/environments/services/neutron-ovn-dpdk.yaml 447 | when: 448 | - dpdk_interface is defined 449 | - ovn_enabled 450 | 451 | - name: Add dpdk-ovs to enabled services 452 | ansible.builtin.set_fact: 453 | service_envs: "{{ service_envs | union(dpdk_env) }}" 454 | vars: 455 | dpdk_env: 456 | - /usr/share/openstack-tripleo-heat-templates/environments/services/neutron-ovs.yaml 457 | - /usr/share/openstack-tripleo-heat-templates/environments/services/neutron-ovs-dpdk.yaml 458 | when: 459 | - dpdk_interface is defined 460 | - not ovn_enabled 461 | 462 | - name: Reduce the number of workers 463 | ansible.builtin.set_fact: 464 | service_envs: "{{ service_envs | union(lowmem_env) }}" 465 | vars: 466 | lowmem_env: 467 | - /usr/share/openstack-tripleo-heat-templates/environments/low-memory-usage.yaml 468 | when: low_memory_usage 469 | 470 | - name: Create default_tripleo_envs fact 471 | ansible.builtin.set_fact: 472 | default_tripleo_envs: 473 | - /usr/share/openstack-tripleo-heat-templates/environments/standalone/standalone-tripleo.yaml 474 | - "{{ ansible_env.HOME }}/containers-prepare-parameters.yaml" 475 | 476 | - name: Create tripleo_override_envs fact 477 | ansible.builtin.set_fact: 478 | tripleo_override_envs: 479 | - "{{ ansible_env.HOME }}/standalone_parameters.yaml" 480 | 481 | # Until https://review.opendev.org/c/openstack/tripleo-heat-templates/+/793836 482 | # is merged upstream. 483 | - name: Create the VIP env file 484 | ansible.builtin.copy: 485 | dest: /usr/share/openstack-tripleo-heat-templates/environments/external-network-vip.yaml 486 | content: | 487 | resource_registry: 488 | OS::TripleO::Network::Ports::ExternalVipPort: ../network/ports/external_from_pool.yaml 489 | mode: '644' 490 | become: true 491 | become_user: root 492 | 493 | - name: Block to figure out if --standalone needs to be passed when deploying tripleo 494 | when: 495 | - ansible_facts.distribution == 'CentOS' 496 | block: 497 | - name: Check if the version of TripleO is recent enough to remove --standalone argument 498 | ansible.builtin.set_fact: 499 | standalone_toggle: false 500 | when: 501 | - (tripleo_repos_branch is defined and tripleo_repos_branch not in ['train', 'ussuri', 'victoria']) or (tripleo_repos_branch is not defined) 502 | 503 | - name: Deploy Ceph 504 | ansible.builtin.include_role: 505 | name: ceph 506 | when: 507 | - ceph_enabled 508 | 509 | - name: Run TripleO deploy 510 | ansible.builtin.import_role: 511 | name: tripleo.operator.tripleo_deploy 512 | vars: 513 | openstack_bin: sudo openstack 514 | tripleo_deploy_deployment_user: stack 515 | tripleo_deploy_standalone: "{{ standalone_toggle | default(true) }}" 516 | tripleo_deploy_output_dir: "{{ ansible_env.HOME }}" 517 | tripleo_deploy_local_ip: "{{ local_ip }}" 518 | tripleo_deploy_control_virtual_ip: "{{ control_plane_ip }}" 519 | tripleo_deploy_public_virtual_ip: "{{ public_api }}" 520 | tripleo_deploy_environment_files: "{{ default_tripleo_envs + service_envs + tripleo_override_envs }}" 521 | tripleo_deploy_generate_scripts: true 522 | tripleo_deploy_keep_running: true 523 | tripleo_deploy_home_dir: "{{ ansible_env.HOME }}" 524 | tripleo_deploy_roles_file: "{{ ansible_env.HOME }}/tripleo_standalone_role.yaml" 525 | tripleo_deploy_networks_file: /usr/share/openstack-tripleo-heat-templates/network_data_undercloud.yaml 526 | 527 | - name: Export Stack data for DCN in /home/stack/exported-data 528 | when: 529 | - dcn_az is defined 530 | - dcn_az == "central" 531 | ansible.builtin.script: files/export-dcn.sh 532 | 533 | - name: Unregister the system from RHSM 534 | become: true 535 | become_user: root 536 | when: 537 | - ansible_facts.distribution == 'RedHat' 538 | - rhsm_enabled 539 | - rhsm_ephemeral 540 | block: 541 | - name: Unregister Red Hat Subscription Manager 542 | ansible.builtin.import_role: 543 | name: redhat-subscription 544 | tasks_from: unregister.yml 545 | 546 | - name: Reboot to apply kernel changes 547 | when: 548 | # if a new condition is added here, it needs to match with the block in `playbooks/prepare_host.yaml`. 549 | - sriov_interface is defined or dpdk_interface is defined or kernel_args is defined 550 | block: 551 | - name: Reboot the node 552 | become: true 553 | ansible.builtin.reboot: 554 | - name: Pause for 2 minutes to let all containers to start and OpenStack to be ready 555 | ansible.builtin.pause: 556 | minutes: 2 557 | --------------------------------------------------------------------------------