feat(octavia): add role
diff --git a/atmosphere/flows.py b/atmosphere/flows.py
index bda7fae..3086da6 100644
--- a/atmosphere/flows.py
+++ b/atmosphere/flows.py
@@ -123,6 +123,9 @@
name=constants.HELM_RELEASE_NOVA_NAME,
),
openstack_helm.ApplyRabbitmqClusterTask(
+ name=constants.HELM_RELEASE_OCTAVIA_NAME,
+ ),
+ openstack_helm.ApplyRabbitmqClusterTask(
name=constants.HELM_RELEASE_SENLIN_NAME,
),
openstack_helm.ApplyRabbitmqClusterTask(
diff --git a/atmosphere/tasks/constants.py b/atmosphere/tasks/constants.py
index 30cc587..9cc9fd7 100644
--- a/atmosphere/tasks/constants.py
+++ b/atmosphere/tasks/constants.py
@@ -422,6 +422,8 @@
HELM_RELEASE_NOVA_NAME = "nova"
+HELM_RELEASE_OCTAVIA_NAME = "octavia"
+
HELM_RELEASE_SENLIN_NAME = "senlin"
HELM_RELEASE_HEAT_NAME = "heat"
diff --git a/playbooks/openstack.yml b/playbooks/openstack.yml
index c6e2584..fb422c8 100644
--- a/playbooks/openstack.yml
+++ b/playbooks/openstack.yml
@@ -109,6 +109,10 @@
tags:
- openstack-helm-heat
+ - role: openstack_helm_octavia
+ tags:
+ - openstack-helm-octavia
+
- role: openstack_helm_horizon
tags:
- openstack-helm-horizon
diff --git a/releasenotes/notes/octavia-init-role-52a84e39a2d222a4.yaml b/releasenotes/notes/octavia-init-role-52a84e39a2d222a4.yaml
new file mode 100644
index 0000000..2f5d537
--- /dev/null
+++ b/releasenotes/notes/octavia-init-role-52a84e39a2d222a4.yaml
@@ -0,0 +1,3 @@
+---
+features:
+ - Add octavia role
diff --git a/roles/openstack_helm_octavia/defaults/main.yml b/roles/openstack_helm_octavia/defaults/main.yml
new file mode 100644
index 0000000..dbdc255
--- /dev/null
+++ b/roles/openstack_helm_octavia/defaults/main.yml
@@ -0,0 +1,67 @@
+---
+# .. vim: foldmarker=[[[,]]]:foldmethod=marker
+
+# .. Copyright (C) 2022 VEXXHOST, Inc.
+# .. SPDX-License-Identifier: Apache-2.0
+
+# Default variables
+# =================
+
+# .. contents:: Sections
+# :local:
+
+
+# .. envvar:: openstack_helm_octavia_image_repository [[[
+#
+# Image repository location to be prefixed for all images
+openstack_helm_octavia_image_repository: "{{ atmosphere_image_repository | default('quay.io/vexxhost') }}"
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_image_tag [[[
+#
+# Image tag for container
+openstack_helm_octavia_image_tag: zed
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_heat_image_tag [[[
+#
+# Image tag for Heat to be used for jobs running via Helm hooks
+openstack_helm_octavia_heat_image_tag: zed
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_neutron_image_tag [[[
+#
+# Image tag for Neutron to be used for openvswitch_vswitchd
+openstack_helm_octavia_neutron_image_tag: zed
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_values [[[
+#
+# Overrides for Helm chart values
+openstack_helm_octavia_values: {}
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_ingress_annotations [[[
+#
+# Ingress annotations
+openstack_helm_octavia_ingress_annotations: {}
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_heartbeat_key [[[
+#
+# Heartbeat key
+openstack_helm_octavia_heartbeat_key: "{{ undef(hint='You must specify a Octavia heartbeat key') }}"
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_management_subnet_cidr [[[
+#
+# Octavia management subnet (CIDR)
+openstack_helm_octavia_management_subnet_cidr: "172.24.0.0/22"
+
+ # ]]]
+# .. envvar:: openstack_helm_octavia_amphora_image_url [[[
+#
+# Octavia amphora image url
+openstack_helm_octavia_amphora_image_url: "https://tarballs.opendev.org/openstack/octavia/test-images/test-only-amphora-x64-haproxy-ubuntu-focal.qcow2"
+
+ # ]]]
diff --git a/roles/openstack_helm_octavia/meta/main.yml b/roles/openstack_helm_octavia/meta/main.yml
new file mode 100644
index 0000000..181e9ad
--- /dev/null
+++ b/roles/openstack_helm_octavia/meta/main.yml
@@ -0,0 +1,27 @@
+# Copyright (c) 2022 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+galaxy_info:
+ author: VEXXHOST, Inc.
+ description: Ansible role for OpenStack Octavia
+ license: Apache-2.0
+ min_ansible_version: 5.5.0
+ platforms:
+ - name: Ubuntu
+ versions:
+ - focal
+
+dependencies:
+ - role: openstacksdk
+ - role: openstack_cli
diff --git a/roles/openstack_helm_octavia/tasks/main.yml b/roles/openstack_helm_octavia/tasks/main.yml
new file mode 100644
index 0000000..967da01
--- /dev/null
+++ b/roles/openstack_helm_octavia/tasks/main.yml
@@ -0,0 +1,285 @@
+# Copyright (c) 2022 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Generate OpenStack-Helm endpoints
+ ansible.builtin.include_role:
+ name: openstack_helm_endpoints
+ vars:
+ openstack_helm_endpoints_repo_name: openstack-helm
+ openstack_helm_endpoints_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+ openstack_helm_endpoints_chart: octavia
+
+- name: Create management network
+ openstack.cloud.network:
+ cloud: atmosphere
+ # Network settings
+ name: lb-mgmt-net
+ register: _openstack_helm_octavia_management_network
+
+- name: Create management subnet
+ openstack.cloud.subnet:
+ cloud: atmosphere
+ # Subnet settings
+ network_name: lb-mgmt-net
+ name: lb-mgmt-subnet
+ cidr: "{{ openstack_helm_octavia_management_subnet_cidr }}"
+
+- name: Create health manager security group
+ openstack.cloud.security_group:
+ cloud: atmosphere
+ name: lb-health-mgr-sec-grp
+ register: _openstack_helm_octavia_health_manager_sg
+
+- name: Create health manager security group rules
+ openstack.cloud.security_group_rule:
+ cloud: atmosphere
+ security_group: "{{ _openstack_helm_octavia_health_manager_sg.id }}"
+ direction: ingress
+ ethertype: IPv4
+ protocol: tcp
+ port_range_min: "{{ item }}"
+ port_range_max: "{{ item }}"
+ loop:
+ - 5555
+ - 10514
+ - 20514
+
+- name: Create health manager networking ports
+ openstack.cloud.port:
+ cloud: atmosphere
+ name: "octavia-health-manager-port-{{ hostvars[item]['inventory_hostname_short'] }}"
+ device_owner: octavia:health-mgr
+ network: "{{ _openstack_helm_octavia_management_network.id }}"
+ security_groups:
+ - "{{ _openstack_helm_octavia_health_manager_sg.id }}"
+ loop: "{{ groups['controllers'] }}"
+
+- name: Set binding for ports
+ changed_when: false
+ ansible.builtin.shell: |
+ openstack port set \
+ --host {{ hostvars[item]['ansible_fqdn'] }} \
+ octavia-health-manager-port-{{ hostvars[item]['inventory_hostname_short'] }}
+ environment:
+ OS_CLOUD: atmosphere
+ loop: "{{ groups['controllers'] }}"
+
+- name: Get health manager networking ports
+ openstack.cloud.port_info:
+ cloud: atmosphere
+ port: "octavia-health-manager-port-{{ hostvars[item]['ansible_fqdn'] | split('.') | first }}"
+ loop: "{{ groups['controllers'] }}"
+ register: _openstack_helm_octavia_health_manager_ports
+
+- name: Set controller_ip_port_list
+ ansible.builtin.set_fact:
+ _openstack_helm_octavia_controller_ip_port_list: "{{ _openstack_helm_octavia_controller_ip_port_list | d([]) + [item.openstack_ports[0].fixed_ips[0].ip_address + ':5555'] }}"
+ loop: "{{ _openstack_helm_octavia_health_manager_ports.results }}"
+
+- name: Create amphora security group
+ openstack.cloud.security_group:
+ cloud: atmosphere
+ name: lb-mgmt-sec-grp
+ register: _openstack_helm_octavia_amphora_sg
+
+- name: Create amphora security group rules
+ openstack.cloud.security_group_rule:
+ cloud: atmosphere
+ security_group: "{{ _openstack_helm_octavia_amphora_sg.id }}"
+ direction: ingress
+ ethertype: IPv4
+ protocol: tcp
+ port_range_min: "{{ item.0 }}"
+ port_range_max: "{{ item.0 }}"
+ remote_ip_prefix: "{{ item.1.openstack_ports[0].fixed_ips[0].ip_address }}/32"
+ with_nested:
+ - [22, 9443]
+ - "{{ _openstack_helm_octavia_health_manager_ports.results }}"
+
+- name: Create amphora flavor
+ openstack.cloud.compute_flavor:
+ cloud: atmosphere
+ name: "m1.amphora"
+ vcpus: "1"
+ ram: "1024"
+ disk: "2"
+ is_public: false
+ register: _openstack_helm_octavia_amphora_flavor
+
+- name: Download amphora image
+ ansible.builtin.get_url:
+ url: "{{ openstack_helm_octavia_amphora_image_url }}"
+ dest: "/tmp/{{ openstack_helm_octavia_amphora_image_url | basename }}"
+ mode: 0644
+
+- name: Upload images
+ openstack.cloud.image:
+ cloud: atmosphere
+ name: "amphora-x64-haproxy"
+ filename: "/tmp/{{ openstack_helm_octavia_amphora_image_url | basename }}"
+ container_format: "bare"
+ disk_format: "qcow2"
+ tags:
+ - "amphora"
+ register: _openstack_helm_octavia_amphora_image
+
+- name: Check if certificate secret exists
+ kubernetes.core.k8s_info:
+ kind: Secret
+ name: octavia-certs
+ namespace: openstack
+ register: _openstack_helm_octavia_cert_secret
+
+# TODO(mnaser): we should just use cert-manager for this?
+- name: Create certificate secret
+ when: (_openstack_helm_octavia_cert_secret.resources | length) == 0
+ block:
+ - name: Create CA private key
+ community.crypto.openssl_privatekey_pipe:
+ type: RSA
+ register: _openstack_helm_octavia_ca_key
+
+ - name: Create certificate signing request (CSR) for CA
+ community.crypto.openssl_csr_pipe:
+ basic_constraints:
+ - 'CA:TRUE'
+ basic_constraints_critical: true
+ common_name: "octavia"
+ key_usage:
+ - "keyEncipherment"
+ - "digitalSignature"
+ - "keyCertSign"
+ key_usage_critical: true
+ organization_name: "VEXXHOST OpenStack - Octavia"
+ privatekey_content: "{{ _openstack_helm_octavia_ca_key.privatekey }}"
+ use_common_name_for_san: false
+ register: _openstack_helm_octavia_ca_csr
+
+ - name: Create self-signed CA certificate from CSR
+ community.crypto.x509_certificate_pipe:
+ csr_content: "{{ _openstack_helm_octavia_ca_csr.csr }}"
+ entrust_not_after: "+3650d"
+ privatekey_content: "{{ _openstack_helm_octavia_ca_key.privatekey }}"
+ provider: selfsigned
+ register: _openstack_helm_octavia_ca
+
+ - name: Create client private key
+ community.crypto.openssl_privatekey_pipe:
+ type: RSA
+ register: _openstack_helm_octavia_client_ca_key
+
+ - name: Create certificate signing request (CSR) for client
+ community.crypto.openssl_csr_pipe:
+ common_name: "octavia-node"
+ key_usage:
+ - "keyEncipherment"
+ - "digitalSignature"
+ - "keyCertSign"
+ organization_name: "VEXXHOST OpenStack - Octavia"
+ privatekey_content: "{{ _openstack_helm_octavia_client_ca_key.privatekey }}"
+ use_common_name_for_san: false
+ register: _openstack_helm_octavia_client_csr
+
+ - name: Create self-signed client certificate
+ community.crypto.x509_certificate_pipe:
+ csr_content: "{{ _openstack_helm_octavia_client_csr.csr }}"
+ ownca_content: "{{ _openstack_helm_octavia_ca.certificate }}"
+ ownca_privatekey_content: "{{ _openstack_helm_octavia_ca_key.privatekey }}"
+ ownca_not_after: "+3650d"
+ entrust_not_after: "+3650d"
+ privatekey_content: "{{ _openstack_helm_octavia_client_ca_key.privatekey }}"
+ provider: ownca
+ register: _openstack_helm_octavia_client_ca
+
+ - name: Createa kubernetes secret
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Secret
+ metadata:
+ name: octavia-certs
+ namespace: openstack
+ stringData:
+ ca_01.pem: |
+ {{ _openstack_helm_octavia_ca.certificate }}
+ cakey.pem: |
+ {{ _openstack_helm_octavia_ca_key.privatekey }}
+ client.pem: |
+ {{ _openstack_helm_octavia_client_ca.certificate }}
+ {{ _openstack_helm_octavia_client_ca_key.privatekey }}
+
+- name: Create admin compute quotaset
+ openstack.cloud.quota:
+ cloud: atmosphere
+ # NOTE(okozachenko): It uses project name instead of id.
+ name: admin
+ instances: -1
+ cores: -1
+ ram: -1
+
+- name: Deploy Helm chart
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ - apiVersion: v1
+ kind: Secret
+ metadata:
+ name: atmosphere-octavia
+ namespace: openstack
+ stringData:
+ values.yaml: "{{ _openstack_helm_octavia_values | combine(openstack_helm_octavia_values, recursive=True) | to_nice_yaml }}"
+
+ - apiVersion: helm.toolkit.fluxcd.io/v2beta1
+ kind: HelmRelease
+ metadata:
+ name: octavia
+ namespace: openstack
+ spec:
+ interval: 60s
+ chart:
+ spec:
+ chart: octavia
+ version: 0.2.5
+ sourceRef:
+ kind: HelmRepository
+ name: openstack-helm
+ install:
+ disableWait: true
+ upgrade:
+ disableWait: true
+ valuesFrom:
+ - kind: Secret
+ name: atmosphere-octavia
+ - kind: Secret
+ name: percona-xtradb
+ valuesKey: root
+ targetPath: endpoints.oslo_db.auth.admin.password
+ - kind: Secret
+ name: rabbitmq-octavia-default-user
+ valuesKey: username
+ targetPath: endpoints.oslo_messaging.auth.admin.username
+ - kind: Secret
+ name: rabbitmq-octavia-default-user
+ valuesKey: password
+ targetPath: endpoints.oslo_messaging.auth.admin.password
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: load_balancer
+ openstack_helm_ingress_service_name: octavia-api
+ openstack_helm_ingress_service_port: 9876
+ openstack_helm_ingress_annotations: "{{ openstack_helm_octavia_ingress_annotations }}"
diff --git a/roles/openstack_helm_octavia/vars/main.yml b/roles/openstack_helm_octavia/vars/main.yml
new file mode 100644
index 0000000..e34a990
--- /dev/null
+++ b/roles/openstack_helm_octavia/vars/main.yml
@@ -0,0 +1,135 @@
+# Copyright (c) 2022 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+_openstack_helm_octavia_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_octavia_image_repository }}/heat:{{ openstack_helm_octavia_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_octavia_image_repository }}/heat:{{ openstack_helm_octavia_heat_image_tag }}"
+ db_init: "{{ openstack_helm_octavia_image_repository }}/heat:{{ openstack_helm_octavia_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_octavia_image_repository }}/kubernetes-entrypoint:latest"
+ ks_endpoints: "{{ openstack_helm_octavia_image_repository }}/heat:{{ openstack_helm_octavia_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_octavia_image_repository }}/heat:{{ openstack_helm_octavia_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_octavia_image_repository }}/heat:{{ openstack_helm_octavia_heat_image_tag }}"
+ rabbit_init: "{{ openstack_helm_octavia_image_repository }}/rabbitmq:3.8.23-management"
+ octavia_api: "{{ openstack_helm_octavia_image_repository }}/octavia:{{ openstack_helm_octavia_image_tag }}"
+ octavia_db_sync: "{{ openstack_helm_octavia_image_repository }}/octavia:{{ openstack_helm_octavia_image_tag }}"
+ octavia_health_manager: "{{ openstack_helm_octavia_image_repository }}/octavia:{{ openstack_helm_octavia_image_tag }}"
+ octavia_health_manager_init: "{{ openstack_helm_octavia_image_repository }}/heat:{{ openstack_helm_octavia_heat_image_tag }}"
+ octavia_housekeeping: "{{ openstack_helm_octavia_image_repository }}/octavia:{{ openstack_helm_octavia_image_tag }}"
+ octavia_worker: "{{ openstack_helm_octavia_image_repository }}/octavia:{{ openstack_helm_octavia_image_tag }}"
+ openvswitch_vswitchd: "{{ openstack_helm_octavia_image_repository }}/neutron:{{ openstack_helm_octavia_neutron_image_tag }}"
+ pod:
+ mounts:
+ octavia_api:
+ octavia_api:
+ volumeMounts:
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/private/cakey.pem"
+ subPath: "cakey.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/ca_01.pem"
+ subPath: "ca_01.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/client.pem"
+ subPath: "client.pem"
+ volumes:
+ - name: octavia-certs
+ secret:
+ secretName: octavia-certs
+ octavia_worker:
+ octavia_worker:
+ volumeMounts:
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/private/cakey.pem"
+ subPath: "cakey.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/ca_01.pem"
+ subPath: "ca_01.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/client.pem"
+ subPath: "client.pem"
+ volumes:
+ - name: octavia-certs
+ secret:
+ secretName: octavia-certs
+ octavia_housekeeping:
+ octavia_housekeeping:
+ volumeMounts:
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/private/cakey.pem"
+ subPath: "cakey.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/ca_01.pem"
+ subPath: "ca_01.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/client.pem"
+ subPath: "client.pem"
+ volumes:
+ - name: octavia-certs
+ secret:
+ secretName: octavia-certs
+ octavia_health_manager:
+ octavia_health_manager:
+ volumeMounts:
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/private/cakey.pem"
+ subPath: "cakey.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/ca_01.pem"
+ subPath: "ca_01.pem"
+ - name: octavia-certs
+ mountPath: "/etc/octavia/certs/client.pem"
+ subPath: "client.pem"
+ volumes:
+ - name: octavia-certs
+ secret:
+ secretName: octavia-certs
+ replicas:
+ api: 3
+ worker: 3
+ housekeeping: 3
+ conf:
+ octavia:
+ DEFAULT:
+ log_config_append: null
+ certificates:
+ ca_private_key_passphrase: null
+ endpoint_type: internalURL
+ cinder:
+ endpoint_type: internalURL
+ controller_worker:
+ amp_boot_network_list: "{{ _openstack_helm_octavia_management_network.id }}"
+ amp_flavor_id: "{{ _openstack_helm_octavia_amphora_flavor.id }}"
+ amp_image_owner_id: "{{ _openstack_helm_octavia_amphora_image.image.owner }}"
+ amp_secgroup_list: "{{ _openstack_helm_octavia_amphora_sg.id }}"
+ amp_ssh_key_name: null
+ workers: 4
+ glance:
+ endpoint_type: internalURL
+ health_manager:
+ controller_ip_port_list: "{{ _openstack_helm_octavia_controller_ip_port_list | join(',') }}"
+ heartbeat_key: "{{ openstack_helm_octavia_heartbeat_key }}"
+ oslo_messaging_notifications:
+ driver: noop
+ neutron:
+ endpoint_type: internalURL
+ nova:
+ endpoint_type: internalURL
+ service_auth:
+ endpoint_type: internalURL
+ manifests:
+ ingress_api: false
+ service_ingress_api: false