Added OpenStack services
Change-Id: I9aadad2919a6a7400d6f11a884317e33e787b416
diff --git a/molecule/default/requirements.txt b/molecule/default/requirements.txt
index 4f5af9e..7f9f540 100644
--- a/molecule/default/requirements.txt
+++ b/molecule/default/requirements.txt
@@ -1 +1,2 @@
+molecule==3.5.2 # https://github.com/ansible-community/molecule/issues/3435
openstacksdk
\ No newline at end of file
diff --git a/playbooks/openstack.yml b/playbooks/openstack.yml
new file mode 100644
index 0000000..31d0a04
--- /dev/null
+++ b/playbooks/openstack.yml
@@ -0,0 +1,112 @@
+# 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.
+
+- hosts: controllers[0]
+ gather_facts: false
+ become: true
+ roles:
+ - role: cilium
+ tags:
+ - cilium
+
+ - role: ceph_csi_rbd
+ tags:
+ - ceph-csi-rbd
+
+ - role: kube_prometheus_stack
+ tags:
+ - kube-prometheus-stack
+
+ - role: node_feature_discovery
+ tags:
+ - node-feature-discovery
+
+ - role: prometheus_pushgateway
+ tags:
+ - prometheus-pushgateway
+
+ - role: openstack_namespace
+ tags:
+ - openstack-namespace
+
+ - role: ingress_nginx
+ tags:
+ - ingress-nginx
+
+ - role: cert_manager
+ tags:
+ - cert-manager
+
+ - role: percona_xtradb_cluster
+ tags:
+ - percona-xtradb-cluster
+
+ - role: openstack_helm_infra_memcached
+ tags:
+ - openstack-helm-infra-memcached
+
+ - role: openstack_helm_infra_rabbitmq
+ tags:
+ - openstack-helm-infra-rabbitmq
+
+ - role: openstack_helm_keystone
+ tags:
+ - openstack-helm-keystone
+
+ - role: openstack_helm_infra_ceph_provisioners
+ tags:
+ - openstack-helm-infra-ceph-provisioners
+
+ - role: openstack_helm_glance
+ tags:
+ - openstack-helm-glance
+
+ - role: openstack_helm_cinder
+ tags:
+ - openstack-helm-cinder
+
+ - role: openstack_helm_placement
+ tags:
+ - openstack-helm-placement
+
+ - role: openstack_helm_infra_openvswitch
+ tags:
+ - openstack-helm-infra-openvswitch
+
+ - role: openstack_helm_infra_libvirt
+ tags:
+ - openstack-helm-infra-libvirt
+
+ - role: openstack_helm_neutron
+ tags:
+ - openstack-helm-neutron
+
+ - role: openstack_helm_nova
+ tags:
+ - openstack-helm-nova
+
+ - role: openstack_helm_heat
+ tags:
+ - openstack-helm-heat
+
+ - role: openstack_helm_horizon
+ tags:
+ - openstack-helm-horizon
+
+- hosts: controllers
+ gather_facts: false
+ roles:
+ - role: openstack_cli
+ tags:
+ - openstack-cli
diff --git a/playbooks/site.yml b/playbooks/site.yml
index 2b745d4..2966d48 100644
--- a/playbooks/site.yml
+++ b/playbooks/site.yml
@@ -14,3 +14,4 @@
- import_playbook: vexxhost.atmosphere.ceph
- import_playbook: vexxhost.atmosphere.kubernetes
+- import_playbook: vexxhost.atmosphere.openstack
diff --git a/plugins/module_utils/ca_common.py b/plugins/module_utils/ca_common.py
new file mode 100644
index 0000000..380463b
--- /dev/null
+++ b/plugins/module_utils/ca_common.py
@@ -0,0 +1,114 @@
+import os
+import datetime
+
+
+def generate_ceph_cmd(sub_cmd, args, user_key=None, cluster='ceph', user='client.admin', container_image=None, interactive=False):
+ '''
+ Generate 'ceph' command line to execute
+ '''
+
+ if not user_key:
+ user_key = '/etc/ceph/{}.{}.keyring'.format(cluster, user)
+
+ cmd = pre_generate_ceph_cmd(
+ container_image=container_image, interactive=interactive)
+
+ base_cmd = [
+ '-n',
+ user,
+ '-k',
+ user_key,
+ '--cluster',
+ cluster
+ ]
+ base_cmd.extend(sub_cmd)
+ cmd.extend(base_cmd + args)
+
+ return cmd
+
+
+def container_exec(binary, container_image, interactive=False):
+ '''
+ Build the docker CLI to run a command inside a container
+ '''
+
+ container_binary = os.getenv('CEPH_CONTAINER_BINARY')
+ command_exec = [container_binary, 'run']
+
+ if interactive:
+ command_exec.extend(['--interactive'])
+
+ command_exec.extend(['--rm',
+ '--net=host',
+ '-v', '/etc/ceph:/etc/ceph:z',
+ '-v', '/var/lib/ceph/:/var/lib/ceph/:z',
+ '-v', '/var/log/ceph/:/var/log/ceph/:z',
+ '--entrypoint=' + binary, container_image])
+ return command_exec
+
+
+def is_containerized():
+ '''
+ Check if we are running on a containerized cluster
+ '''
+
+ if 'CEPH_CONTAINER_IMAGE' in os.environ:
+ container_image = os.getenv('CEPH_CONTAINER_IMAGE')
+ else:
+ container_image = None
+
+ return container_image
+
+
+def pre_generate_ceph_cmd(container_image=None, interactive=False):
+ '''
+ Generate ceph prefix comaand
+ '''
+ if container_image:
+ cmd = container_exec('ceph', container_image, interactive=interactive)
+ else:
+ cmd = ['ceph']
+
+ return cmd
+
+
+def exec_command(module, cmd, stdin=None):
+ '''
+ Execute command(s)
+ '''
+
+ binary_data = False
+ if stdin:
+ binary_data = True
+ rc, out, err = module.run_command(cmd, data=stdin, binary_data=binary_data)
+
+ return rc, cmd, out, err
+
+
+def exit_module(module, out, rc, cmd, err, startd, changed=False, diff=dict(before="", after="")):
+ endd = datetime.datetime.now()
+ delta = endd - startd
+
+ result = dict(
+ cmd=cmd,
+ start=str(startd),
+ end=str(endd),
+ delta=str(delta),
+ rc=rc,
+ stdout=out.rstrip("\r\n"),
+ stderr=err.rstrip("\r\n"),
+ changed=changed,
+ diff=diff
+ )
+ module.exit_json(**result)
+
+
+def fatal(message, module):
+ '''
+ Report a fatal error and exit
+ '''
+
+ if module:
+ module.fail_json(msg=message, rc=1)
+ else:
+ raise(Exception(message))
diff --git a/plugins/modules/ceph_key.py b/plugins/modules/ceph_key.py
new file mode 100644
index 0000000..437a0d3
--- /dev/null
+++ b/plugins/modules/ceph_key.py
@@ -0,0 +1,692 @@
+#!/usr/bin/python3
+
+# Copyright 2018, Red Hat, 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.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.vexxhost.atmosphere.plugins.module_utils.ca_common import generate_ceph_cmd, \
+ is_containerized, \
+ container_exec, \
+ fatal
+
+import datetime
+import json
+import os
+import struct
+import time
+import base64
+import socket
+
+
+ANSIBLE_METADATA = {
+ 'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'community'
+}
+
+DOCUMENTATION = '''
+---
+module: ceph_key
+
+author: Sebastien Han <seb@redhat.com>
+
+short_description: Manage Cephx key(s)
+
+version_added: "2.6"
+
+description:
+ - Manage CephX creation, deletion and updates.
+ It can also list and get information about keyring(s).
+options:
+ cluster:
+ description:
+ - The ceph cluster name.
+ required: false
+ default: ceph
+ name:
+ description:
+ - name of the CephX key
+ required: true
+ user:
+ description:
+ - entity used to perform operation.
+ It corresponds to the -n option (--name)
+ required: false
+ user_key:
+ description:
+ - the path to the keyring corresponding to the
+ user being used.
+ It corresponds to the -k option (--keyring)
+ state:
+ description:
+ - If 'present' is used, the module creates a keyring
+ with the associated capabilities.
+ If 'present' is used and a secret is provided the module
+ will always add the key. Which means it will update
+ the keyring if the secret changes, the same goes for
+ the capabilities.
+ If 'absent' is used, the module will simply delete the keyring.
+ If 'list' is used, the module will list all the keys and will
+ return a json output.
+ If 'info' is used, the module will return in a json format the
+ description of a given keyring.
+ If 'generate_secret' is used, the module will simply output a cephx keyring.
+ required: false
+ choices: ['present', 'update', 'absent', 'list', 'info', 'fetch_initial_keys', 'generate_secret']
+ default: present
+ caps:
+ description:
+ - CephX key capabilities
+ default: None
+ required: false
+ secret:
+ description:
+ - keyring's secret value
+ required: false
+ default: None
+ import_key:
+ description:
+ - Wether or not to import the created keyring into Ceph.
+ This can be useful for someone that only wants to generate keyrings
+ but not add them into Ceph.
+ required: false
+ default: True
+ dest:
+ description:
+ - Destination to write the keyring, can a file or a directory
+ required: false
+ default: /etc/ceph/
+ fetch_initial_keys:
+ description:
+ - Fetch client.admin and bootstrap key.
+ This is only needed for Nautilus and above.
+ Writes down to the filesystem the initial keys generated by the monitor. # noqa: E501
+ This command can ONLY run from a monitor node.
+ required: false
+ default: false
+ output_format:
+ description:
+ - The key output format when retrieving the information of an
+ entity.
+ required: false
+ default: json
+'''
+
+EXAMPLES = '''
+
+keys_to_create:
+ - { name: client.key, key: "AQAin8tUUK84ExAA/QgBtI7gEMWdmnvKBzlXdQ==", caps: { mon: "allow rwx", mds: "allow *" } , mode: "0600" } # noqa: E501
+ - { name: client.cle, caps: { mon: "allow r", osd: "allow *" } , mode: "0600" } # noqa: E501
+
+caps:
+ mon: "allow rwx"
+ mds: "allow *"
+
+- name: create ceph admin key
+ ceph_key:
+ name: client.admin
+ state: present
+ secret: AQAin8tU2DsKFBAAFIAzVTzkL3+gtAjjpQiomw==
+ caps:
+ mon: allow *
+ osd: allow *
+ mgr: allow *
+ mds: allow
+ mode: 0400
+ import_key: False
+
+- name: create monitor initial keyring
+ ceph_key:
+ name: mon.
+ state: present
+ secret: AQAin8tUMICVFBAALRHNrV0Z4MXupRw4v9JQ6Q==
+ caps:
+ mon: allow *
+ dest: "/var/lib/ceph/tmp/"
+ import_key: False
+
+- name: create cephx key
+ ceph_key:
+ name: "{{ keys_to_create }}"
+ user: client.bootstrap-rgw
+ user_key: /var/lib/ceph/bootstrap-rgw/ceph.keyring
+ state: present
+ caps: "{{ caps }}"
+
+- name: create cephx key but don't import it in Ceph
+ ceph_key:
+ name: "{{ keys_to_create }}"
+ state: present
+ caps: "{{ caps }}"
+ import_key: False
+
+- name: delete cephx key
+ ceph_key:
+ name: "my_key"
+ state: absent
+
+- name: info cephx key
+ ceph_key:
+ name: "my_key""
+ state: info
+
+- name: info cephx admin key (plain)
+ ceph_key:
+ name: client.admin
+ output_format: plain
+ state: info
+ register: client_admin_key
+
+- name: list cephx keys
+ ceph_key:
+ state: list
+
+- name: fetch cephx keys
+ ceph_key:
+ state: fetch_initial_keys
+'''
+
+RETURN = '''# '''
+
+
+CEPH_INITIAL_KEYS = ['client.admin', 'client.bootstrap-mds', 'client.bootstrap-mgr', # noqa: E501
+ 'client.bootstrap-osd', 'client.bootstrap-rbd', 'client.bootstrap-rbd-mirror', 'client.bootstrap-rgw'] # noqa: E501
+
+
+def str_to_bool(val):
+ try:
+ val = val.lower()
+ except AttributeError:
+ val = str(val).lower()
+ if val == 'true':
+ return True
+ elif val == 'false':
+ return False
+ else:
+ raise ValueError("Invalid input value: %s" % val)
+
+
+def generate_secret():
+ '''
+ Generate a CephX secret
+ '''
+
+ key = os.urandom(16)
+ header = struct.pack('<hiih', 1, int(time.time()), 0, len(key))
+ secret = base64.b64encode(header + key)
+
+ return secret
+
+
+def generate_caps(_type, caps):
+ '''
+ Generate CephX capabilities list
+ '''
+
+ caps_cli = []
+
+ for k, v in caps.items():
+ # makes sure someone didn't pass an empty var,
+ # we don't want to add an empty cap
+ if len(k) == 0:
+ continue
+ if _type == "ceph-authtool":
+ caps_cli.extend(["--cap"])
+ caps_cli.extend([k, v])
+
+ return caps_cli
+
+
+def generate_ceph_authtool_cmd(cluster, name, secret, caps, dest, container_image=None): # noqa: E501
+ '''
+ Generate 'ceph-authtool' command line to execute
+ '''
+
+ if container_image:
+ binary = 'ceph-authtool'
+ cmd = container_exec(
+ binary, container_image)
+ else:
+ binary = ['ceph-authtool']
+ cmd = binary
+
+ base_cmd = [
+ '--create-keyring',
+ dest,
+ '--name',
+ name,
+ '--add-key',
+ secret,
+ ]
+
+ cmd.extend(base_cmd)
+ cmd.extend(generate_caps("ceph-authtool", caps))
+
+ return cmd
+
+
+def create_key(module, result, cluster, user, user_key, name, secret, caps, import_key, dest, container_image=None): # noqa: E501
+ '''
+ Create a CephX key
+ '''
+
+ cmd_list = []
+ if not secret:
+ secret = generate_secret()
+
+ if user == 'client.admin':
+ args = ['import', '-i', dest]
+ else:
+ args = ['get-or-create', name]
+ args.extend(generate_caps(None, caps))
+ args.extend(['-o', dest])
+
+ cmd_list.append(generate_ceph_authtool_cmd(
+ cluster, name, secret, caps, dest, container_image))
+
+ if import_key or user != 'client.admin':
+ cmd_list.append(generate_ceph_cmd(sub_cmd=['auth'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image))
+
+ return cmd_list
+
+
+def delete_key(cluster, user, user_key, name, container_image=None):
+ '''
+ Delete a CephX key
+ '''
+
+ cmd_list = []
+
+ args = [
+ 'del',
+ name,
+ ]
+
+ cmd_list.append(generate_ceph_cmd(sub_cmd=['auth'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image))
+
+ return cmd_list
+
+
+def get_key(cluster, user, user_key, name, dest, container_image=None):
+ '''
+ Get a CephX key (write on the filesystem)
+ '''
+
+ cmd_list = []
+
+ args = [
+ 'get',
+ name,
+ '-o',
+ dest,
+ ]
+
+ cmd_list.append(generate_ceph_cmd(sub_cmd=['auth'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image))
+
+ return cmd_list
+
+
+def info_key(cluster, name, user, user_key, output_format, container_image=None): # noqa: E501
+ '''
+ Get information about a CephX key
+ '''
+
+ cmd_list = []
+
+ args = [
+ 'get',
+ name,
+ '-f',
+ output_format,
+ ]
+
+ cmd_list.append(generate_ceph_cmd(sub_cmd=['auth'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image))
+
+ return cmd_list
+
+
+def list_keys(cluster, user, user_key, container_image=None):
+ '''
+ List all CephX keys
+ '''
+
+ cmd_list = []
+
+ args = [
+ 'ls',
+ '-f',
+ 'json',
+ ]
+
+ cmd_list.append(generate_ceph_cmd(sub_cmd=['auth'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image))
+
+ return cmd_list
+
+
+def exec_commands(module, cmd_list):
+ '''
+ Execute command(s)
+ '''
+
+ for cmd in cmd_list:
+ rc, out, err = module.run_command(cmd)
+ if rc != 0:
+ return rc, cmd, out, err
+
+ return rc, cmd, out, err
+
+
+def lookup_ceph_initial_entities(module, out):
+ '''
+ Lookup Ceph initial keys entries in the auth map
+ '''
+
+ # convert out to json, ansible returns a string...
+ try:
+ out_dict = json.loads(out)
+ except ValueError as e:
+ fatal("Could not decode 'ceph auth list' json output: {}".format(e), module) # noqa: E501
+
+ entities = []
+ if "auth_dump" in out_dict:
+ for key in out_dict["auth_dump"]:
+ for k, v in key.items():
+ if k == "entity":
+ if v in CEPH_INITIAL_KEYS:
+ entities.append(v)
+ else:
+ fatal("'auth_dump' key not present in json output:", module) # noqa: E501
+
+ if len(entities) != len(CEPH_INITIAL_KEYS) and not str_to_bool(os.environ.get('CEPH_ROLLING_UPDATE', False)): # noqa: E501
+ # must be missing in auth_dump, as if it were in CEPH_INITIAL_KEYS
+ # it'd be in entities from the above test. Report what's missing.
+ missing = []
+ for e in CEPH_INITIAL_KEYS:
+ if e not in entities:
+ missing.append(e)
+ fatal("initial keyring does not contain keys: " + ' '.join(missing), module) # noqa: E501
+ return entities
+
+
+def build_key_path(cluster, entity):
+ '''
+ Build key path depending on the key type
+ '''
+
+ if "admin" in entity:
+ path = "/etc/ceph"
+ keyring_filename = cluster + "." + entity + ".keyring"
+ key_path = os.path.join(path, keyring_filename)
+ elif "bootstrap" in entity:
+ path = "/var/lib/ceph"
+ # bootstrap keys show up as 'client.boostrap-osd'
+ # however the directory is called '/var/lib/ceph/bootstrap-osd'
+ # so we need to substring 'client.'
+ entity_split = entity.split('.')[1]
+ keyring_filename = cluster + ".keyring"
+ key_path = os.path.join(path, entity_split, keyring_filename)
+ else:
+ return None
+
+ return key_path
+
+
+def run_module():
+ module_args = dict(
+ cluster=dict(type='str', required=False, default='ceph'),
+ name=dict(type='str', required=False),
+ state=dict(type='str', required=False, default='present', choices=['present', 'update', 'absent', # noqa: E501
+ 'list', 'info', 'fetch_initial_keys', 'generate_secret']), # noqa: E501
+ caps=dict(type='dict', required=False, default=None),
+ secret=dict(type='str', required=False, default=None, no_log=True),
+ import_key=dict(type='bool', required=False, default=True),
+ dest=dict(type='str', required=False, default='/etc/ceph/'),
+ user=dict(type='str', required=False, default='client.admin'),
+ user_key=dict(type='str', required=False, default=None),
+ output_format=dict(type='str', required=False, default='json', choices=['json', 'plain', 'xml', 'yaml']) # noqa: E501
+ )
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ supports_check_mode=True,
+ add_file_common_args=True,
+ )
+
+ file_args = module.load_file_common_arguments(module.params)
+
+ # Gather module parameters in variables
+ state = module.params['state']
+ name = module.params.get('name')
+ cluster = module.params.get('cluster')
+ caps = module.params.get('caps')
+ secret = module.params.get('secret')
+ import_key = module.params.get('import_key')
+ dest = module.params.get('dest')
+ user = module.params.get('user')
+ user_key = module.params.get('user_key')
+ output_format = module.params.get('output_format')
+
+ changed = False
+
+ result = dict(
+ changed=changed,
+ stdout='',
+ stderr='',
+ rc=0,
+ start='',
+ end='',
+ delta='',
+ )
+
+ if module.check_mode and state != "info":
+ module.exit_json(**result)
+
+ startd = datetime.datetime.now()
+
+ # will return either the image name or None
+ container_image = is_containerized()
+
+ # Test if the key exists, if it does we skip its creation
+ # We only want to run this check when a key needs to be added
+ # There is no guarantee that any cluster is running and we don't need one
+ _secret = secret
+ _caps = caps
+ key_exist = 1
+
+ if not user_key:
+ user_key_filename = '{}.{}.keyring'.format(cluster, user)
+ user_key_dir = '/etc/ceph'
+ user_key_path = os.path.join(user_key_dir, user_key_filename)
+ else:
+ user_key_path = user_key
+
+ if (state in ["present", "update"]):
+ # if dest is not a directory, the user wants to change the file's name
+ # (e,g: /etc/ceph/ceph.mgr.ceph-mon2.keyring)
+ if not os.path.isdir(dest):
+ file_path = dest
+ else:
+ if 'bootstrap' in dest:
+ # Build a different path for bootstrap keys as there are stored
+ # as /var/lib/ceph/bootstrap-rbd/ceph.keyring
+ keyring_filename = cluster + '.keyring'
+ else:
+ keyring_filename = cluster + "." + name + ".keyring"
+ file_path = os.path.join(dest, keyring_filename)
+
+ file_args['path'] = file_path
+
+ if import_key:
+ _info_key = []
+ rc, cmd, out, err = exec_commands(
+ module, info_key(cluster, name, user, user_key_path, output_format, container_image)) # noqa: E501
+ key_exist = rc
+ if not caps and key_exist != 0:
+ fatal("Capabilities must be provided when state is 'present'", module) # noqa: E501
+ if key_exist != 0 and secret is None and caps is None:
+ fatal("Keyring doesn't exist, you must provide 'secret' and 'caps'", module) # noqa: E501
+ if key_exist == 0:
+ _info_key = json.loads(out)
+ if not secret:
+ secret = _info_key[0]['key']
+ _secret = _info_key[0]['key']
+ if not caps:
+ caps = _info_key[0]['caps']
+ _caps = _info_key[0]['caps']
+ if secret == _secret and caps == _caps:
+ if not os.path.isfile(file_path):
+ rc, cmd, out, err = exec_commands(module, get_key(cluster, user, user_key_path, name, file_path, container_image)) # noqa: E501
+ result["rc"] = rc
+ if rc != 0:
+ result["stdout"] = "Couldn't fetch the key {0} at {1}.".format(name, file_path) # noqa: E501
+ module.exit_json(**result)
+ result["stdout"] = "fetched the key {0} at {1}.".format(name, file_path) # noqa: E501
+
+ result["stdout"] = "{0} already exists and doesn't need to be updated.".format(name) # noqa: E501
+ result["rc"] = 0
+ module.set_fs_attributes_if_different(file_args, False)
+ module.exit_json(**result)
+ else:
+ if os.path.isfile(file_path) and not secret or not caps:
+ result["stdout"] = "{0} already exists in {1} you must provide secret *and* caps when import_key is {2}".format(name, dest, import_key) # noqa: E501
+ result["rc"] = 0
+ module.exit_json(**result)
+ if (key_exist == 0 and (secret != _secret or caps != _caps)) or key_exist != 0: # noqa: E501
+ rc, cmd, out, err = exec_commands(module, create_key(
+ module, result, cluster, user, user_key_path, name, secret, caps, import_key, file_path, container_image)) # noqa: E501
+ if rc != 0:
+ result["stdout"] = "Couldn't create or update {0}".format(name)
+ result["stderr"] = err
+ module.exit_json(**result)
+ module.set_fs_attributes_if_different(file_args, False)
+ changed = True
+
+ elif state == "absent":
+ if key_exist == 0:
+ rc, cmd, out, err = exec_commands(
+ module, delete_key(cluster, user, user_key_path, name, container_image)) # noqa: E501
+ if rc == 0:
+ changed = True
+ else:
+ rc = 0
+
+ elif state == "info":
+ rc, cmd, out, err = exec_commands(
+ module, info_key(cluster, name, user, user_key_path, output_format, container_image)) # noqa: E501
+
+ elif state == "list":
+ rc, cmd, out, err = exec_commands(
+ module, list_keys(cluster, user, user_key_path, container_image))
+
+ elif state == "fetch_initial_keys":
+ hostname = socket.gethostname().split('.', 1)[0]
+ user = "mon."
+ keyring_filename = cluster + "-" + hostname + "/keyring"
+ user_key_path = os.path.join("/var/lib/ceph/mon/", keyring_filename)
+ rc, cmd, out, err = exec_commands(
+ module, list_keys(cluster, user, user_key_path, container_image))
+ if rc != 0:
+ result["stdout"] = "failed to retrieve ceph keys"
+ result["sdterr"] = err
+ result['rc'] = 0
+ module.exit_json(**result)
+
+ entities = lookup_ceph_initial_entities(module, out)
+
+ output_format = "plain"
+ for entity in entities:
+ key_path = build_key_path(cluster, entity)
+ if key_path is None:
+ fatal("Failed to build key path, no entity yet?", module)
+ elif os.path.isfile(key_path):
+ # if the key is already on the filesystem
+ # there is no need to fetch it again
+ continue
+
+ extra_args = [
+ '-o',
+ key_path,
+ ]
+
+ info_cmd = info_key(cluster, entity, user,
+ user_key_path, output_format, container_image)
+ # we use info_cmd[0] because info_cmd is an array made of an array
+ info_cmd[0].extend(extra_args)
+ rc, cmd, out, err = exec_commands(
+ module, info_cmd) # noqa: E501
+
+ file_args = module.load_file_common_arguments(module.params)
+ file_args['path'] = key_path
+ module.set_fs_attributes_if_different(file_args, False)
+ elif state == "generate_secret":
+ out = generate_secret().decode()
+ cmd = ''
+ rc = 0
+ err = ''
+ changed = True
+
+ endd = datetime.datetime.now()
+ delta = endd - startd
+
+ result = dict(
+ cmd=cmd,
+ start=str(startd),
+ end=str(endd),
+ delta=str(delta),
+ rc=rc,
+ stdout=out.rstrip("\r\n"),
+ stderr=err.rstrip("\r\n"),
+ changed=changed,
+ )
+
+ if rc != 0:
+ module.fail_json(msg='non-zero return code', **result)
+
+ module.exit_json(**result)
+
+
+def main():
+ run_module()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/plugins/modules/ceph_pool.py b/plugins/modules/ceph_pool.py
new file mode 100644
index 0000000..ff91f76
--- /dev/null
+++ b/plugins/modules/ceph_pool.py
@@ -0,0 +1,684 @@
+#!/usr/bin/python3
+
+# Copyright 2020, Red Hat, 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.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible_collections.vexxhost.atmosphere.plugins.module_utils.ca_common import generate_ceph_cmd, \
+ pre_generate_ceph_cmd, \
+ is_containerized, \
+ exec_command, \
+ exit_module
+
+import datetime
+import json
+import os
+
+
+ANSIBLE_METADATA = {
+ 'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'community'
+}
+
+DOCUMENTATION = '''
+---
+module: ceph_pool
+
+author: Guillaume Abrioux <gabrioux@redhat.com>
+
+short_description: Manage Ceph Pools
+
+version_added: "2.8"
+
+description:
+ - Manage Ceph pool(s) creation, deletion and updates.
+options:
+ cluster:
+ description:
+ - The ceph cluster name.
+ required: false
+ default: ceph
+ name:
+ description:
+ - name of the Ceph pool
+ required: true
+ state:
+ description:
+ If 'present' is used, the module creates a pool if it doesn't exist
+ or update it if it already exists.
+ If 'absent' is used, the module will simply delete the pool.
+ If 'list' is used, the module will return all details about the
+ existing pools. (json formatted).
+ required: false
+ choices: ['present', 'absent', 'list']
+ default: present
+ size:
+ description:
+ - set the replica size of the pool.
+ required: false
+ default: 3
+ min_size:
+ description:
+ - set the min_size parameter of the pool.
+ required: false
+ default: default to `osd_pool_default_min_size` (ceph)
+ pg_num:
+ description:
+ - set the pg_num of the pool.
+ required: false
+ default: default to `osd_pool_default_pg_num` (ceph)
+ pgp_num:
+ description:
+ - set the pgp_num of the pool.
+ required: false
+ default: default to `osd_pool_default_pgp_num` (ceph)
+ pg_autoscale_mode:
+ description:
+ - set the pg autoscaler on the pool.
+ required: false
+ default: 'on'
+ target_size_ratio:
+ description:
+ - set the target_size_ratio on the pool
+ required: false
+ default: None
+ pool_type:
+ description:
+ - set the pool type, either 'replicated' or 'erasure'
+ required: false
+ default: 'replicated'
+ erasure_profile:
+ description:
+ - When pool_type = 'erasure', set the erasure profile of the pool
+ required: false
+ default: 'default'
+ rule_name:
+ description:
+ - Set the crush rule name assigned to the pool
+ required: false
+ default: 'replicated_rule' when pool_type is 'erasure' else None
+ expected_num_objects:
+ description:
+ - Set the expected_num_objects parameter of the pool.
+ required: false
+ default: '0'
+ application:
+ description:
+ - Set the pool application on the pool.
+ required: false
+ default: None
+'''
+
+EXAMPLES = '''
+
+pools:
+ - { name: foo, size: 3, application: rbd, pool_type: 'replicated',
+ pg_autoscale_mode: 'on' }
+
+- hosts: all
+ become: true
+ tasks:
+ - name: create a pool
+ ceph_pool:
+ name: "{{ item.name }}"
+ state: present
+ size: "{{ item.size }}"
+ application: "{{ item.application }}"
+ pool_type: "{{ item.pool_type }}"
+ pg_autoscale_mode: "{{ item.pg_autoscale_mode }}"
+ with_items: "{{ pools }}"
+'''
+
+RETURN = '''# '''
+
+
+def check_pool_exist(cluster,
+ name,
+ user,
+ user_key,
+ output_format='json',
+ container_image=None):
+ '''
+ Check if a given pool exists
+ '''
+
+ args = ['stats', name, '-f', output_format]
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ return cmd
+
+
+def generate_get_config_cmd(param,
+ cluster,
+ user,
+ user_key,
+ container_image=None):
+ _cmd = pre_generate_ceph_cmd(container_image=container_image)
+ args = [
+ '-n',
+ user,
+ '-k',
+ user_key,
+ '--cluster',
+ cluster,
+ 'config',
+ 'get',
+ 'mon.*',
+ param
+ ]
+ cmd = _cmd + args
+ return cmd
+
+
+def get_application_pool(cluster,
+ name,
+ user,
+ user_key,
+ output_format='json',
+ container_image=None):
+ '''
+ Get application type enabled on a given pool
+ '''
+
+ args = ['application', 'get', name, '-f', output_format]
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ return cmd
+
+
+def enable_application_pool(cluster,
+ name,
+ application,
+ user,
+ user_key,
+ container_image=None):
+ '''
+ Enable application on a given pool
+ '''
+
+ args = ['application', 'enable', name, application]
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ return cmd
+
+
+def disable_application_pool(cluster,
+ name,
+ application,
+ user,
+ user_key,
+ container_image=None):
+ '''
+ Disable application on a given pool
+ '''
+
+ args = ['application', 'disable', name,
+ application, '--yes-i-really-mean-it']
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ return cmd
+
+
+def get_pool_details(module,
+ cluster,
+ name,
+ user,
+ user_key,
+ output_format='json',
+ container_image=None):
+ '''
+ Get details about a given pool
+ '''
+
+ args = ['ls', 'detail', '-f', output_format]
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ rc, cmd, out, err = exec_command(module, cmd)
+
+ if rc == 0:
+ out = [p for p in json.loads(out.strip()) if p['pool_name'] == name][0]
+
+ _rc, _cmd, application_pool, _err = exec_command(module,
+ get_application_pool(cluster, # noqa: E501
+ name, # noqa: E501
+ user, # noqa: E501
+ user_key, # noqa: E501
+ container_image=container_image)) # noqa: E501
+
+ # This is a trick because "target_size_ratio" isn't present at the same
+ # level in the dict
+ # ie:
+ # {
+ # 'pg_num': 8,
+ # 'pgp_num': 8,
+ # 'pg_autoscale_mode': 'on',
+ # 'options': {
+ # 'target_size_ratio': 0.1
+ # }
+ # }
+ # If 'target_size_ratio' is present in 'options', we set it, this way we
+ # end up with a dict containing all needed keys at the same level.
+ if 'target_size_ratio' in out['options'].keys():
+ out['target_size_ratio'] = out['options']['target_size_ratio']
+ else:
+ out['target_size_ratio'] = None
+
+ application = list(json.loads(application_pool.strip()).keys())
+
+ if len(application) == 0:
+ out['application'] = ''
+ else:
+ out['application'] = application[0]
+
+ return rc, cmd, out, err
+
+
+def compare_pool_config(user_pool_config, running_pool_details):
+ '''
+ Compare user input config pool details with current running pool details
+ '''
+
+ delta = {}
+ filter_keys = ['pg_num', 'pg_placement_num', 'size',
+ 'pg_autoscale_mode', 'target_size_ratio']
+ for key in filter_keys:
+ if (str(running_pool_details[key]) != user_pool_config[key]['value'] and # noqa: E501
+ user_pool_config[key]['value']):
+ delta[key] = user_pool_config[key]
+
+ if (running_pool_details['application'] !=
+ user_pool_config['application']['value'] and
+ user_pool_config['application']['value']):
+ delta['application'] = {}
+ delta['application']['new_application'] = user_pool_config['application']['value'] # noqa: E501
+ # to be improved (for update_pools()...)
+ delta['application']['value'] = delta['application']['new_application']
+ delta['application']['old_application'] = running_pool_details['application'] # noqa: E501
+
+ return delta
+
+
+def list_pools(cluster,
+ user,
+ user_key,
+ details,
+ output_format='json',
+ container_image=None):
+ '''
+ List existing pools
+ '''
+
+ args = ['ls']
+
+ if details:
+ args.append('detail')
+
+ args.extend(['-f', output_format])
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ return cmd
+
+
+def create_pool(cluster,
+ name,
+ user,
+ user_key,
+ user_pool_config,
+ container_image=None):
+ '''
+ Create a new pool
+ '''
+
+ args = ['create', user_pool_config['pool_name']['value'],
+ user_pool_config['type']['value']]
+
+ if user_pool_config['pg_autoscale_mode']['value'] != 'on':
+ args.extend(['--pg_num',
+ user_pool_config['pg_num']['value'],
+ '--pgp_num',
+ user_pool_config['pgp_num']['value'] or
+ user_pool_config['pg_num']['value']])
+ elif user_pool_config['target_size_ratio']['value']:
+ args.extend(['--target_size_ratio',
+ user_pool_config['target_size_ratio']['value']])
+
+ if user_pool_config['type']['value'] == 'replicated':
+ args.extend([user_pool_config['crush_rule']['value'],
+ '--expected_num_objects',
+ user_pool_config['expected_num_objects']['value'],
+ '--autoscale-mode',
+ user_pool_config['pg_autoscale_mode']['value']])
+
+ if (user_pool_config['size']['value'] and
+ user_pool_config['type']['value'] == "replicated"):
+ args.extend(['--size', user_pool_config['size']['value']])
+
+ elif user_pool_config['type']['value'] == 'erasure':
+ args.extend([user_pool_config['erasure_profile']['value']])
+
+ if user_pool_config['crush_rule']['value']:
+ args.extend([user_pool_config['crush_rule']['value']])
+
+ args.extend(['--expected_num_objects',
+ user_pool_config['expected_num_objects']['value'],
+ '--autoscale-mode',
+ user_pool_config['pg_autoscale_mode']['value']])
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ return cmd
+
+
+def remove_pool(cluster, name, user, user_key, container_image=None):
+ '''
+ Remove a pool
+ '''
+
+ args = ['rm', name, name, '--yes-i-really-really-mean-it']
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ return cmd
+
+
+def update_pool(module, cluster, name,
+ user, user_key, delta, container_image=None):
+ '''
+ Update an existing pool
+ '''
+
+ report = ""
+
+ for key in delta.keys():
+ if key != 'application':
+ args = ['set',
+ name,
+ delta[key]['cli_set_opt'],
+ delta[key]['value']]
+
+ cmd = generate_ceph_cmd(sub_cmd=['osd', 'pool'],
+ args=args,
+ cluster=cluster,
+ user=user,
+ user_key=user_key,
+ container_image=container_image)
+
+ rc, cmd, out, err = exec_command(module, cmd)
+ if rc != 0:
+ return rc, cmd, out, err
+
+ else:
+ rc, cmd, out, err = exec_command(module, disable_application_pool(cluster, name, delta['application']['old_application'], user, user_key, container_image=container_image)) # noqa: E501
+ if rc != 0:
+ return rc, cmd, out, err
+
+ rc, cmd, out, err = exec_command(module, enable_application_pool(cluster, name, delta['application']['new_application'], user, user_key, container_image=container_image)) # noqa: E501
+ if rc != 0:
+ return rc, cmd, out, err
+
+ report = report + "\n" + "{} has been updated: {} is now {}".format(name, key, delta[key]['value']) # noqa: E501
+
+ out = report
+ return rc, cmd, out, err
+
+
+def run_module():
+ module_args = dict(
+ cluster=dict(type='str', required=False, default='ceph'),
+ name=dict(type='str', required=True),
+ state=dict(type='str', required=False, default='present',
+ choices=['present', 'absent', 'list']),
+ details=dict(type='bool', required=False, default=False),
+ size=dict(type='str', required=False),
+ min_size=dict(type='str', required=False),
+ pg_num=dict(type='str', required=False),
+ pgp_num=dict(type='str', required=False),
+ pg_autoscale_mode=dict(type='str', required=False, default='on'),
+ target_size_ratio=dict(type='str', required=False, default=None),
+ pool_type=dict(type='str', required=False, default='replicated',
+ choices=['replicated', 'erasure', '1', '3']),
+ erasure_profile=dict(type='str', required=False, default='default'),
+ rule_name=dict(type='str', required=False, default=None),
+ expected_num_objects=dict(type='str', required=False, default="0"),
+ application=dict(type='str', required=False, default=None),
+ )
+
+ module = AnsibleModule(
+ argument_spec=module_args,
+ supports_check_mode=True
+ )
+
+ # Gather module parameters in variables
+ cluster = module.params.get('cluster')
+ name = module.params.get('name')
+ state = module.params.get('state')
+ details = module.params.get('details')
+ size = module.params.get('size')
+ min_size = module.params.get('min_size')
+ pg_num = module.params.get('pg_num')
+ pgp_num = module.params.get('pgp_num')
+ pg_autoscale_mode = module.params.get('pg_autoscale_mode')
+ target_size_ratio = module.params.get('target_size_ratio')
+ application = module.params.get('application')
+
+ if (module.params.get('pg_autoscale_mode').lower() in
+ ['true', 'on', 'yes']):
+ pg_autoscale_mode = 'on'
+ elif (module.params.get('pg_autoscale_mode').lower() in
+ ['false', 'off', 'no']):
+ pg_autoscale_mode = 'off'
+ else:
+ pg_autoscale_mode = 'warn'
+
+ if module.params.get('pool_type') == '1':
+ pool_type = 'replicated'
+ elif module.params.get('pool_type') == '3':
+ pool_type = 'erasure'
+ else:
+ pool_type = module.params.get('pool_type')
+
+ if not module.params.get('rule_name'):
+ rule_name = 'replicated_rule' if pool_type == 'replicated' else None
+ else:
+ rule_name = module.params.get('rule_name')
+
+ erasure_profile = module.params.get('erasure_profile')
+ expected_num_objects = module.params.get('expected_num_objects')
+ user_pool_config = {
+ 'pool_name': {'value': name},
+ 'pg_num': {'value': pg_num, 'cli_set_opt': 'pg_num'},
+ 'pgp_num': {'value': pgp_num, 'cli_set_opt': 'pgp_num'},
+ 'pg_autoscale_mode': {'value': pg_autoscale_mode,
+ 'cli_set_opt': 'pg_autoscale_mode'},
+ 'target_size_ratio': {'value': target_size_ratio,
+ 'cli_set_opt': 'target_size_ratio'},
+ 'application': {'value': application},
+ 'type': {'value': pool_type},
+ 'erasure_profile': {'value': erasure_profile},
+ 'crush_rule': {'value': rule_name, 'cli_set_opt': 'crush_rule'},
+ 'expected_num_objects': {'value': expected_num_objects},
+ 'size': {'value': size, 'cli_set_opt': 'size'},
+ 'min_size': {'value': min_size}
+ }
+
+ if module.check_mode:
+ module.exit_json(
+ changed=False,
+ stdout='',
+ stderr='',
+ rc=0,
+ start='',
+ end='',
+ delta='',
+ )
+
+ startd = datetime.datetime.now()
+ changed = False
+
+ # will return either the image name or None
+ container_image = is_containerized()
+
+ user = "client.admin"
+ keyring_filename = cluster + '.' + user + '.keyring'
+ user_key = os.path.join("/etc/ceph/", keyring_filename)
+
+ if state == "present":
+ rc, cmd, out, err = exec_command(module,
+ check_pool_exist(cluster,
+ name,
+ user,
+ user_key,
+ container_image=container_image)) # noqa: E501
+ if rc == 0:
+ running_pool_details = get_pool_details(module,
+ cluster,
+ name,
+ user,
+ user_key,
+ container_image=container_image) # noqa: E501
+ user_pool_config['pg_placement_num'] = {'value': str(running_pool_details[2]['pg_placement_num']), 'cli_set_opt': 'pgp_num'} # noqa: E501
+ delta = compare_pool_config(user_pool_config,
+ running_pool_details[2])
+ if len(delta) > 0:
+ keys = list(delta.keys())
+ details = running_pool_details[2]
+ if details['erasure_code_profile'] and 'size' in keys:
+ del delta['size']
+ if details['pg_autoscale_mode'] == 'on':
+ delta.pop('pg_num', None)
+ delta.pop('pgp_num', None)
+
+ if len(delta) == 0:
+ out = "Skipping pool {}.\nUpdating either 'size' on an erasure-coded pool or 'pg_num'/'pgp_num' on a pg autoscaled pool is incompatible".format(name) # noqa: E501
+ else:
+ rc, cmd, out, err = update_pool(module,
+ cluster,
+ name,
+ user,
+ user_key,
+ delta,
+ container_image=container_image) # noqa: E501
+ if rc == 0:
+ changed = True
+ else:
+ out = "Pool {} already exists and there is nothing to update.".format(name) # noqa: E501
+ else:
+ rc, cmd, out, err = exec_command(module,
+ create_pool(cluster,
+ name,
+ user,
+ user_key,
+ user_pool_config=user_pool_config, # noqa: E501
+ container_image=container_image)) # noqa: E501
+ if user_pool_config['application']['value']:
+ rc, _, _, _ = exec_command(module,
+ enable_application_pool(cluster,
+ name,
+ user_pool_config['application']['value'], # noqa: E501
+ user,
+ user_key,
+ container_image=container_image)) # noqa: E501
+ if user_pool_config['min_size']['value']:
+ # not implemented yet
+ pass
+ changed = True
+
+ elif state == "list":
+ rc, cmd, out, err = exec_command(module,
+ list_pools(cluster,
+ name, user,
+ user_key,
+ details,
+ container_image=container_image)) # noqa: E501
+ if rc != 0:
+ out = "Couldn't list pool(s) present on the cluster"
+
+ elif state == "absent":
+ rc, cmd, out, err = exec_command(module,
+ check_pool_exist(cluster,
+ name, user,
+ user_key,
+ container_image=container_image)) # noqa: E501
+ if rc == 0:
+ rc, cmd, out, err = exec_command(module,
+ remove_pool(cluster,
+ name,
+ user,
+ user_key,
+ container_image=container_image)) # noqa: E501
+ changed = True
+ else:
+ rc = 0
+ out = "Skipped, since pool {} doesn't exist".format(name)
+
+ exit_module(module=module, out=out, rc=rc, cmd=cmd, err=err, startd=startd,
+ changed=changed)
+
+
+def main():
+ run_module()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/roles/ceph_csi_rbd/defaults/main.yml b/roles/ceph_csi_rbd/defaults/main.yml
new file mode 100644
index 0000000..fc16f2d
--- /dev/null
+++ b/roles/ceph_csi_rbd/defaults/main.yml
@@ -0,0 +1,20 @@
+# 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.
+
+ceph_csi_rbd_ceph_fsid: "{{ ceph_mon_fsid }}"
+ceph_csi_rbd_mons_group: ceph_mons
+
+ceph_csi_rbd_id: kube
+ceph_csi_rbd_user: "client.{{ ceph_csi_rbd_id }}"
+ceph_csi_rbd_pool: kube
diff --git a/roles/ceph_csi_rbd/meta/main.yml b/roles/ceph_csi_rbd/meta/main.yml
new file mode 100644
index 0000000..b3836f8
--- /dev/null
+++ b/roles/ceph_csi_rbd/meta/main.yml
@@ -0,0 +1,20 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: ceph
+ helm_repository_repo_url: https://ceph.github.io/csi-charts
+ - cilium
diff --git a/roles/ceph_csi_rbd/tasks/main.yml b/roles/ceph_csi_rbd/tasks/main.yml
new file mode 100644
index 0000000..43e8498
--- /dev/null
+++ b/roles/ceph_csi_rbd/tasks/main.yml
@@ -0,0 +1,72 @@
+# 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: collect facts for all monitors
+ run_once: true
+ delegate_to: "{{ item }}"
+ delegate_facts: true
+ ansible.builtin.setup:
+ gather_subset: network
+ loop: "{{ groups[ceph_csi_rbd_mons_group] }}"
+
+- vexxhost.atmosphere.ceph_pool:
+ name: "{{ ceph_csi_rbd_pool }}"
+ application: rbd
+ pg_autoscale_mode: on
+
+- vexxhost.atmosphere.ceph_key:
+ name: "{{ ceph_csi_rbd_user }}"
+ caps:
+ mon: profile rbd
+ mgr: profile rbd pool={{ ceph_csi_rbd_pool }}
+ osd: profile rbd pool={{ ceph_csi_rbd_pool }}
+
+- vexxhost.atmosphere.ceph_key:
+ name: "{{ ceph_csi_rbd_user }}"
+ state: info
+ output_format: json
+ register: _ceph_key
+
+- ansible.builtin.set_fact:
+ _ceph_rbd_csi_ceph_keyring: "{{ _ceph_key.stdout | from_json | first }}"
+
+- kubernetes.core.helm:
+ name: ceph-csi-rbd
+ chart_ref: ceph/ceph-csi-rbd
+ chart_version: 3.5.1
+ release_namespace: kube-system
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ csiConfig:
+ - clusterID: "{{ ceph_mon_fsid }}"
+ monitors: "{{ groups[ceph_csi_rbd_mons_group] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) }}"
+ nodeplugin:
+ httpMetrics:
+ containerPort: 8081
+ provisioner:
+ nodeSelector:
+ openstack-control-plane: enabled
+ storageClass:
+ create: true
+ name: general
+ annotations:
+ storageclass.kubernetes.io/is-default-class: "true"
+ clusterID: "{{ ceph_csi_rbd_ceph_fsid }}"
+ pool: "{{ ceph_csi_rbd_pool }}"
+ mountOptions:
+ - discard
+ secret:
+ create: true
+ userID: "{{ ceph_csi_rbd_id }}"
+ userKey: "{{ _ceph_rbd_csi_ceph_keyring.key }}"
diff --git a/roles/cert_manager/defaults/main.yml b/roles/cert_manager/defaults/main.yml
new file mode 100644
index 0000000..45415d9
--- /dev/null
+++ b/roles/cert_manager/defaults/main.yml
@@ -0,0 +1,26 @@
+# 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.
+
+cert_manager_acme_server: https://acme-v02.api.letsencrypt.org/directory
+
+cert_manager_issuer:
+ acme:
+ email: mnaser@vexxhost.com
+ server: "{{ cert_manager_acme_server }}"
+ privateKeySecretRef:
+ name: issuer-account-key
+ solvers:
+ - http01:
+ ingress:
+ class: openstack
diff --git a/roles/cert_manager/meta/main.yml b/roles/cert_manager/meta/main.yml
new file mode 100644
index 0000000..1cf4a6e
--- /dev/null
+++ b/roles/cert_manager/meta/main.yml
@@ -0,0 +1,22 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: jetstack
+ helm_repository_repo_url: https://charts.jetstack.io
+ - cilium
+ - ingress_nginx
+ - openstack_namespace
diff --git a/roles/cert_manager/tasks/main.yml b/roles/cert_manager/tasks/main.yml
new file mode 100644
index 0000000..b06b4f6
--- /dev/null
+++ b/roles/cert_manager/tasks/main.yml
@@ -0,0 +1,43 @@
+# 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: Deploy Helm chart
+ kubernetes.core.helm:
+ name: cert-manager
+ chart_ref: jetstack/cert-manager
+ chart_version: v1.7.1
+ release_namespace: cert-manager
+ create_namespace: true
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ installCRDs: true
+ volumes:
+ - name: etc-ssl-certs
+ hostPath:
+ path: /etc/ssl/certs
+ volumeMounts:
+ - name: etc-ssl-certs
+ mountPath: /etc/ssl/certs
+ readOnly: true
+
+- name: Create issuer
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: cert-manager.io/v1
+ kind: Issuer
+ metadata:
+ name: openstack
+ namespace: openstack
+ spec: "{{ cert_manager_issuer }}"
diff --git a/roles/cilium/meta/main.yml b/roles/cilium/meta/main.yml
new file mode 100644
index 0000000..fda3c18
--- /dev/null
+++ b/roles/cilium/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: cilium
+ helm_repository_repo_url: https://helm.cilium.io/
diff --git a/roles/cilium/tasks/main.yml b/roles/cilium/tasks/main.yml
new file mode 100644
index 0000000..98b5bb9
--- /dev/null
+++ b/roles/cilium/tasks/main.yml
@@ -0,0 +1,21 @@
+# 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: Deploy Helm chart
+ kubernetes.core.helm:
+ name: cilium
+ chart_ref: cilium/cilium
+ chart_version: 1.10.7
+ release_namespace: kube-system
+ kubeconfig: /etc/kubernetes/admin.conf
diff --git a/roles/helm_diff/tasks/main.yml b/roles/helm_diff/tasks/main.yml
new file mode 100644
index 0000000..909e650
--- /dev/null
+++ b/roles/helm_diff/tasks/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.
+
+- name: Retrieve values for current Helm release
+ kubernetes.core.helm_info:
+ name: "{{ helm_diff_release_name }}"
+ release_namespace: "{{ helm_diff_release_namespace }}"
+ register: _helm_diff_info
+
+- name: Generate diff between old and new values
+ ansible.utils.fact_diff:
+ before: "{{ _helm_diff_info.status['values'] }}"
+ after: "{{ helm_diff_values }}"
+
+- name: Pause until you can verify values are correct
+ ansible.builtin.pause:
diff --git a/roles/helm_repository/meta/main.yml b/roles/helm_repository/meta/main.yml
new file mode 100644
index 0000000..05e1c2d
--- /dev/null
+++ b/roles/helm_repository/meta/main.yml
@@ -0,0 +1,16 @@
+# 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.
+
+dependencies:
+ - helm
diff --git a/roles/helm_repository/tasks/main.yml b/roles/helm_repository/tasks/main.yml
new file mode 100644
index 0000000..a7dd7e2
--- /dev/null
+++ b/roles/helm_repository/tasks/main.yml
@@ -0,0 +1,18 @@
+# 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: Configure Helm repository ({{ helm_repository_name }})
+ kubernetes.core.helm_repository:
+ name: "{{ helm_repository_name }}"
+ repo_url: "{{ helm_repository_repo_url }}"
diff --git a/roles/ingress_nginx/meta/main.yml b/roles/ingress_nginx/meta/main.yml
new file mode 100644
index 0000000..bde6443
--- /dev/null
+++ b/roles/ingress_nginx/meta/main.yml
@@ -0,0 +1,20 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: ingress-nginx
+ helm_repository_repo_url: https://kubernetes.github.io/ingress-nginx
+ - openstack_namespace
diff --git a/roles/ingress_nginx/tasks/main.yml b/roles/ingress_nginx/tasks/main.yml
new file mode 100644
index 0000000..6436383
--- /dev/null
+++ b/roles/ingress_nginx/tasks/main.yml
@@ -0,0 +1,39 @@
+# 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: Deploy Helm chart
+ kubernetes.core.helm:
+ name: ingress-nginx
+ chart_ref: ingress-nginx/ingress-nginx
+ chart_version: 4.0.17
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ controller:
+ config:
+ proxy-buffer-size: 16k
+ dnsPolicy: ClusterFirstWithHostNet
+ hostNetwork: true
+ ingressClassResource:
+ name: openstack
+ ingressClass: openstack
+ extraArgs:
+ default-ssl-certificate: ingress-nginx/wildcard
+ kind: DaemonSet
+ nodeSelector:
+ openstack-control-plane: enabled
+ service:
+ type: ClusterIP
+ admissionWebhooks:
+ port: 7443
diff --git a/roles/kube_prometheus_stack/meta/main.yml b/roles/kube_prometheus_stack/meta/main.yml
new file mode 100644
index 0000000..137f7b5
--- /dev/null
+++ b/roles/kube_prometheus_stack/meta/main.yml
@@ -0,0 +1,21 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: prometheus-community
+ helm_repository_repo_url: https://prometheus-community.github.io/helm-charts
+ - cilium
+ - ceph_csi_rbd
diff --git a/roles/kube_prometheus_stack/tasks/main.yml b/roles/kube_prometheus_stack/tasks/main.yml
new file mode 100644
index 0000000..22c3e4d
--- /dev/null
+++ b/roles/kube_prometheus_stack/tasks/main.yml
@@ -0,0 +1,270 @@
+# 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.
+
+- ansible.builtin.slurp:
+ src: /etc/kubernetes/pki/etcd/ca.crt
+ register: _etcd_ca_crt
+
+- ansible.builtin.slurp:
+ src: /etc/kubernetes/pki/etcd/healthcheck-client.crt
+ register: _etcd_healthcheck_client_crt
+
+- ansible.builtin.slurp:
+ src: /etc/kubernetes/pki/etcd/healthcheck-client.key
+ register: _etcd_healthcheck_client_key
+
+- kubernetes.core.helm:
+ name: kube-prometheus-stack
+ chart_ref: prometheus-community/kube-prometheus-stack
+ chart_version: 30.2.0
+ release_namespace: monitoring
+ create_namespace: true
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ alertmanager:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ grafana:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ kubeApiServer:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_node_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ kubelet:
+ serviceMonitor:
+ cAdvisorRelabelings:
+ - sourceLabels: [__metrics_path__]
+ targetLabel: metrics_path
+ - sourceLabels: ["node"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|node|service)$"
+ probesRelabelings:
+ - sourceLabels: [__metrics_path__]
+ targetLabel: metrics_path
+ - sourceLabels: ["node"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|node|service)$"
+ relabelings:
+ - sourceLabels: [__metrics_path__]
+ targetLabel: metrics_path
+ - sourceLabels: ["node"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|node|service)$"
+ kubeControllerManager:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_node_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ coreDns:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - regex: "^(container|endpoint|namespace|pod|service)$"
+ action: "labeldrop"
+ kubeEtcd:
+ serviceMonitor:
+ scheme: https
+ serverName: localhost
+ insecureSkipVerify: false
+ caFile: /etc/prometheus/secrets/kube-prometheus-stack-etcd-client-cert/ca.crt
+ certFile: /etc/prometheus/secrets/kube-prometheus-stack-etcd-client-cert/healthcheck-client.crt
+ keyFile: /etc/prometheus/secrets/kube-prometheus-stack-etcd-client-cert/healthcheck-client.key
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_node_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ kubeScheduler:
+ service:
+ port: 10259
+ targetPort: 10259
+ serviceMonitor:
+ https: true
+ insecureSkipVerify: true
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_node_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ kubeProxy:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_node_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ kube-state-metrics:
+ prometheus:
+ monitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ nodeSelector:
+ openstack-control-plane: enabled
+ prometheus:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ prometheusSpec:
+ nodeSelector:
+ openstack-control-plane: enabled
+ secrets:
+ - kube-prometheus-stack-etcd-client-cert
+ prometheusOperator:
+ serviceMonitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ nodeSelector:
+ openstack-control-plane: enabled
+ prometheus-node-exporter:
+ extraArgs:
+ - --collector.diskstats.ignored-devices=^(ram|loop|nbd|fd|(h|s|v|xv)d[a-z]|nvme\\d+n\\d+p)\\d+$
+ - --collector.filesystem.fs-types-exclude=^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|fuse.squashfuse_ll|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$
+ - --collector.filesystem.mount-points-exclude=^/(dev|proc|run/credentials/.+|sys|var/lib/docker/.+|var/lib/kubelet/pods/.+|var/lib/kubelet/plugins/kubernetes.io/csi/.+|run/containerd/.+)($|/)
+ - --collector.netclass.ignored-devices=^(lxc|cilium_|qbr|qvb|qvo|ovs-system).*$
+ - --collector.netdev.device-exclude=^(lxc|cilium_|qbr|qvb|qvo|ovs-system).*$
+ prometheus:
+ monitor:
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_node_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ additionalPrometheusRulesMap:
+ coredns:
+ groups:
+ - name: coredns
+ rules:
+ - alert: CoreDNSDown
+ expr: absent(up{job="coredns"} == 1)
+ for: 15m
+ labels:
+ severity: critical
+ - alert: CoreDNSLatencyHigh
+ expr: histogram_quantile(0.99, sum(rate(coredns_dns_request_duration_seconds_bucket{job="coredns"}[5m])) by(server, zone, le)) > 4
+ for: 10m
+ labels:
+ severity: critical
+ - alert: CoreDNSErrorsHigh
+ expr: sum(rate(coredns_dns_responses_total{job="coredns",rcode="SERVFAIL"}[5m])) / sum(rate(coredns_dns_responses_total{job="coredns"}[5m])) > 0.01
+ for: 10m
+ labels:
+ severity: warning
+ - alert: CoreDNSErrorsHigh
+ expr: sum(rate(coredns_dns_responses_total{job="coredns",rcode="SERVFAIL"}[5m])) / sum(rate(coredns_dns_responses_total{job="coredns"}[5m])) > 0.03
+ for: 10m
+ labels:
+ severity: critical
+ - name: coredns_forward
+ rules:
+ - alert: CoreDNSForwardLatencyHigh
+ expr: histogram_quantile(0.99, sum(rate(coredns_forward_request_duration_seconds_bucket{job="coredns"}[5m])) by(to, le)) > 4
+ for: 10m
+ labels:
+ severity: critical
+ - alert: CoreDNSForwardErrorsHigh
+ expr: sum(rate(coredns_forward_responses_total{job="coredns",rcode="SERVFAIL"}[5m])) / sum(rate(coredns_forward_responses_total{job="coredns"}[5m])) > 0.01
+ for: 10m
+ labels:
+ severity: warning
+ - alert: CoreDNSForwardErrorsHigh
+ expr: sum(rate(coredns_forward_responses_total{job="coredns",rcode="SERVFAIL"}[5m])) / sum(rate(coredns_forward_responses_total{job="coredns"}[5m])) > 0.03
+ for: 10m
+ labels:
+ severity: critical
+ - alert: CoreDNSForwardHealthcheckFailureCount
+ expr: sum(rate(coredns_forward_healthcheck_failures_total{job="coredns"}[5m])) by (to) > 0
+ for: 2m
+ labels:
+ severity: warning
+ - alert: CoreDNSForwardHealthcheckBrokenCount
+ expr: sum(rate(coredns_forward_healthcheck_broken_total{job="coredns"}[5m])) > 0
+ for: 2m
+ labels:
+ severity: critical
+ node-exporter-local:
+ groups:
+ - name: node
+ rules:
+ - alert: NodeHighLoadAverage
+ expr: node_load5 / count(node_cpu_seconds_total{mode="system"}) without (cpu, mode) > 1.5
+ for: 30m
+ labels:
+ severity: warning
+ - alert: NodeHighMemoryUsage
+ expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 2.5
+ for: 2m
+ labels:
+ severity: critical
+ - alert: NodeHighCpuUsage
+ expr: sum by(instance)(irate(node_cpu_seconds_total{mode='idle'}[5m])) < 1
+ for: 2m
+ labels:
+ severity: warning
+ - alert: NodeLowEntropy
+ expr: node_entropy_available_bits < 1000
+ for: 5m
+ labels:
+ severity: warning
+ - name: softnet
+ rules:
+ - alert: NodeSoftNetTimesSqueezed
+ expr: sum(rate(node_softnet_times_squeezed_total[1m])) by (instance) > 10
+ for: 10m
+ labels:
+ severity: warning
+ - alert: NodeSoftNetDrops
+ expr: sum(rate(node_softnet_dropped_total[1m])) by (instance) != 0
+ for: 1m
+ labels:
+ severity: critical
+
+- kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Secret
+ metadata:
+ name: kube-prometheus-stack-etcd-client-cert
+ namespace: monitoring
+ data:
+ ca.crt: "{{ _etcd_ca_crt.content }}"
+ healthcheck-client.crt: "{{ _etcd_healthcheck_client_crt.content }}"
+ healthcheck-client.key: "{{ _etcd_healthcheck_client_key.content }}"
diff --git a/roles/kubernetes/templates/haproxy.cfg.j2 b/roles/kubernetes/templates/haproxy.cfg.j2
index b4cb838..053ce9a 100644
--- a/roles/kubernetes/templates/haproxy.cfg.j2
+++ b/roles/kubernetes/templates/haproxy.cfg.j2
@@ -47,5 +47,5 @@
option ssl-hello-chk
balance roundrobin
{% for host in groups[kubernetes_control_plane_group] %}
- server {{ host }} {{ hostvars[host]['ansible_host'] }}:16443 check
+ server {{ host }} {{ hostvars[host]['ansible_default_ipv4']['address'] }}:16443 check
{% endfor %}
diff --git a/roles/kubernetes/templates/kubeadm.yaml.j2 b/roles/kubernetes/templates/kubeadm.yaml.j2
index eba1d7c..cc30dfd 100644
--- a/roles/kubernetes/templates/kubeadm.yaml.j2
+++ b/roles/kubernetes/templates/kubeadm.yaml.j2
@@ -7,7 +7,7 @@
kubeletExtraArgs:
cgroups-per-qos: "false"
enforce-node-allocatable: ""
- node-ip: "{{ ansible_host }}"
+ node-ip: "{{ ansible_default_ipv4.address }}"
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: JoinConfiguration
@@ -15,7 +15,7 @@
kubeletExtraArgs:
cgroups-per-qos: "false"
enforce-node-allocatable: ""
- node-ip: "{{ ansible_host }}"
+ node-ip: "{{ ansible_default_ipv4.address }}"
{% if (_kubernetes_bootstrap_node is not defined) or (_kubernetes_bootstrap_node is defined and inventory_hostname != _kubernetes_bootstrap_node) %}
discovery:
bootstrapToken:
diff --git a/roles/node_feature_discovery/meta/main.yml b/roles/node_feature_discovery/meta/main.yml
new file mode 100644
index 0000000..503ce14
--- /dev/null
+++ b/roles/node_feature_discovery/meta/main.yml
@@ -0,0 +1,21 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: node-feature-discovery
+ helm_repository_repo_url: https://kubernetes-sigs.github.io/node-feature-discovery/charts
+ - cilium
+ - kube_prometheus_stack
diff --git a/roles/node_feature_discovery/tasks/main.yml b/roles/node_feature_discovery/tasks/main.yml
new file mode 100644
index 0000000..213c72f
--- /dev/null
+++ b/roles/node_feature_discovery/tasks/main.yml
@@ -0,0 +1,39 @@
+# 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.
+
+- kubernetes.core.helm:
+ name: node-feature-discovery
+ chart_ref: node-feature-discovery/node-feature-discovery
+ chart_version: 0.10.0
+ release_namespace: monitoring
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ image:
+ repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}/node-feature-discovery"
+ tag: 0.10.0
+ master:
+ nodeSelector:
+ openstack-control-plane: enabled
+ worker:
+ config:
+ sources:
+ custom:
+ - name: ipmi
+ labels:
+ ipmi: "true"
+ matchFeatures:
+ - feature: kernel.loadedmodule
+ matchExpresions:
+ ipmi_msghandler:
+ op: Exists
diff --git a/roles/openstack_cli/defaults/main.yml b/roles/openstack_cli/defaults/main.yml
new file mode 100644
index 0000000..8079a74
--- /dev/null
+++ b/roles/openstack_cli/defaults/main.yml
@@ -0,0 +1,16 @@
+# 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_cli_packages:
+ - python3-openstackclient
diff --git a/roles/openstack_cli/tasks/main.yml b/roles/openstack_cli/tasks/main.yml
new file mode 100644
index 0000000..b1c032a
--- /dev/null
+++ b/roles/openstack_cli/tasks/main.yml
@@ -0,0 +1,33 @@
+# 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: Install OpenStack client
+ become: true
+ ansible.builtin.apt:
+ name: "{{ openstack_cli_packages }}"
+
+- name: Generate OpenStack-Helm endpoints
+ ansible.builtin.include_role:
+ name: openstack_helm_endpoints
+ vars:
+ openstack_helm_endpoints_list: ["identity"]
+
+- name: Generate openrc file
+ become: true
+ ansible.builtin.template:
+ src: openrc.j2
+ dest: /root/openrc
+ owner: root
+ group: root
+ mode: 0600
diff --git a/roles/openstack_cli/templates/openrc.j2 b/roles/openstack_cli/templates/openrc.j2
new file mode 100644
index 0000000..7b56e0f
--- /dev/null
+++ b/roles/openstack_cli/templates/openrc.j2
@@ -0,0 +1,12 @@
+# {{ ansible_managed }}
+
+export OS_IDENTITY_API_VERSION=3
+
+export OS_AUTH_URL="{{ openstack_helm_endpoints['identity']['scheme']['public'] }}://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}/v3"
+export OS_AUTH_TYPE=password
+export OS_REGION_NAME="{{ openstack_helm_endpoints['identity']['auth']['admin']['region_name'] }}"
+export OS_USER_DOMAIN_NAME=Default
+export OS_USERNAME="{{ openstack_helm_endpoints['identity']['auth']['admin']['username'] }}"
+export OS_PASSWORD="{{ openstack_helm_endpoints['identity']['auth']['admin']['password'] }}"
+export OS_PROJECT_DOMAIN_NAME=Default
+export OS_PROJECT_NAME=admin
\ No newline at end of file
diff --git a/roles/openstack_helm_cinder/defaults/main.yml b/roles/openstack_helm_cinder/defaults/main.yml
new file mode 100644
index 0000000..02e5a98
--- /dev/null
+++ b/roles/openstack_helm_cinder/defaults/main.yml
@@ -0,0 +1,23 @@
+# 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_cinder_chart_repo_name: openstack-helm
+openstack_helm_cinder_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_cinder_chart_name: cinder
+
+openstack_helm_cinder_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_cinder_image_tag: 18.1.1.dev29-1
+openstack_helm_cinder_heat_image_tag: wallaby
+
+openstack_helm_cinder_values: {}
diff --git a/roles/openstack_helm_cinder/meta/main.yml b/roles/openstack_helm_cinder/meta/main.yml
new file mode 100644
index 0000000..8ed7540
--- /dev/null
+++ b/roles/openstack_helm_cinder/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_cinder_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_cinder_chart_repo_url }}"
diff --git a/roles/openstack_helm_cinder/tasks/main.yml b/roles/openstack_helm_cinder/tasks/main.yml
new file mode 100644
index 0000000..67fa685
--- /dev/null
+++ b/roles/openstack_helm_cinder/tasks/main.yml
@@ -0,0 +1,41 @@
+# 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_cinder_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_cinder_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_cinder_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_cinder_chart_name }}"
+ chart_ref: "{{ openstack_helm_cinder_chart_repo_name }}/{{ openstack_helm_cinder_chart_name }}"
+ chart_version: 0.2.15
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_cinder_values | combine(openstack_helm_cinder_values, recursive=True) }}"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: volumev3
+ openstack_helm_ingress_service_name: cinder-api
+ openstack_helm_ingress_service_port: 8776
+ openstack_helm_ingress_annotations:
+ nginx.ingress.kubernetes.io/proxy-body-size: "0"
+ nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
diff --git a/roles/openstack_helm_cinder/vars/main.yml b/roles/openstack_helm_cinder/vars/main.yml
new file mode 100644
index 0000000..2b7fef5
--- /dev/null
+++ b/roles/openstack_helm_cinder/vars/main.yml
@@ -0,0 +1,61 @@
+# 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_cinder_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_cinder_image_repository }}/heat:{{ openstack_helm_cinder_heat_image_tag }}"
+ cinder_api: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ cinder_backup_storage_init: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ cinder_backup: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ cinder_db_sync: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ cinder_scheduler: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ cinder_storage_init: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ cinder_volume_usage_audit: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ cinder_volume: "{{ openstack_helm_cinder_image_repository }}/cinder:{{ openstack_helm_cinder_image_tag }}"
+ db_drop: "{{ openstack_helm_cinder_image_repository }}/heat:{{ openstack_helm_cinder_heat_image_tag }}"
+ db_init: "{{ openstack_helm_cinder_image_repository }}/heat:{{ openstack_helm_cinder_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_cinder_image_repository }}/kubernetes-entrypoint:latest"
+ ks_endpoints: "{{ openstack_helm_cinder_image_repository }}/heat:{{ openstack_helm_cinder_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_cinder_image_repository }}/heat:{{ openstack_helm_cinder_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_cinder_image_repository }}/heat:{{ openstack_helm_cinder_heat_image_tag }}"
+ rabbit_init: "{{ openstack_helm_cinder_image_repository }}/rabbitmq:3.8.23-management"
+ pod:
+ replicas:
+ api: 3
+ scheduler: 3
+ conf:
+ paste:
+ composite:openstack_volume_api_v3:
+ use: call:cinder.api.middleware.auth:pipeline_factory
+ noauth: cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth apiv3
+ keystone: cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv3
+ keystone_nolimit: cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv3
+ cinder:
+ DEFAULT:
+ allowed_direct_url_schemes: cinder
+ backup_driver: cinder.backup.drivers.ceph.CephBackupDriver
+ log_config_append: null
+ os_region_name: "{{ openstack_helm_endpoints['identity']['auth']['cinder']['region_name'] }}"
+ volume_usage_audit_period: hour
+ volume_name_template: volume-%s
+ barbican:
+ barbican_endpoint_type: internal
+ cors:
+ allowed_origins: "*"
+ manifests:
+ ingress_api: false
+ job_clean: false
+ service_ingress_api: false
diff --git a/roles/openstack_helm_endpoints/defaults/main.yml b/roles/openstack_helm_endpoints/defaults/main.yml
new file mode 100644
index 0000000..0338286
--- /dev/null
+++ b/roles/openstack_helm_endpoints/defaults/main.yml
@@ -0,0 +1,102 @@
+# 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.
+
+# Base configuration
+openstack_helm_endpoints_region_name: "{{ undef(hint='You must specify an OpenStack region name') }}"
+openstack_helm_endpoints_config: {}
+
+# RabbitMQ
+openstack_helm_endpoints_rabbitmq_erlang_cookie: "{{ undef(hint='You must specify an RabbitMQ Erlang cookie') }}"
+openstack_helm_endpoints_rabbitmq_admin_password: "{{ undef(hint='You must specify a RabbitMQ admin password') }}"
+
+# Memcached
+openstack_helm_endpoints_memcached_secret_key: "{{ undef(hint='You must specify a Memcached secret key') }}"
+
+# Keystone
+openstack_helm_endpoints_keystone_api_host: "{{ undef(hint='You must specify a Keystone API hostname') }}"
+openstack_helm_endpoints_keystone_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_keystone_admin_password: "{{ undef(hint='You must specify a Keystone administrator password') }}"
+openstack_helm_endpoints_keystone_mariadb_password: "{{ undef(hint='You must specify a Keystone MariaDB password') }}"
+openstack_helm_endpoints_keystone_rabbitmq_password: "{{ undef(hint='You must specify a Keystone RabbitMQ password') }}"
+
+# Glance
+openstack_helm_endpoints_glance_api_host: "{{ undef(hint='You must specify a Glance API hostname') }}"
+openstack_helm_endpoints_glance_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_glance_keystone_password: "{{ undef(hint='You must specify a Glance Keystone password') }}"
+openstack_helm_endpoints_glance_mariadb_password: "{{ undef(hint='You must specify a Glance MariaDB password') }}"
+openstack_helm_endpoints_glance_rabbitmq_password: "{{ undef(hint='You must specify a Glance RabbitMQ password') }}"
+
+# Cinder
+openstack_helm_endpoints_cinder_api_host: "{{ undef(hint='You must specify a Cinder API hostname') }}"
+openstack_helm_endpoints_cinder_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_cinder_keystone_password: "{{ undef(hint='You must specify a Cinder Keystone password') }}"
+openstack_helm_endpoints_cinder_mariadb_password: "{{ undef(hint='You must specify a Cinder MariaDB password') }}"
+openstack_helm_endpoints_cinder_rabbitmq_password: "{{ undef(hint='You must specify a Cinder RabbitMQ password') }}"
+
+# Placement
+openstack_helm_endpoints_placement_api_host: "{{ undef(hint='You must specify a Placement API hostname') }}"
+openstack_helm_endpoints_placement_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_placement_keystone_password: "{{ undef(hint='You must specify a Placement Keystone password') }}"
+openstack_helm_endpoints_placement_mariadb_password: "{{ undef(hint='You must specify a Placement MariaDB password') }}"
+
+# Neutron
+openstack_helm_endpoints_neutron_api_host: "{{ undef(hint='You must specify a Neutron API hostname') }}"
+openstack_helm_endpoints_neutron_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_neutron_keystone_password: "{{ undef(hint='You must specify a Neutron Keystone password') }}"
+openstack_helm_endpoints_neutron_mariadb_password: "{{ undef(hint='You must specify a Neutron MariaDB password') }}"
+openstack_helm_endpoints_neutron_rabbitmq_password: "{{ undef(hint='You must specify a Neutron RabbitMQ password') }}"
+openstack_helm_endpoints_neutron_metadata_secret: "{{ undef(hint='You must specify a Neutron metadata secret') }}"
+
+# Nova
+openstack_helm_endpoints_nova_api_host: "{{ undef(hint='You must specify a Nova API hostname') }}"
+openstack_helm_endpoints_nova_novnc_host: "{{ undef(hint='You must specify a Nova NoVNC hostname') }}"
+openstack_helm_endpoints_nova_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_nova_keystone_password: "{{ undef(hint='You must specify a Nova Keystone password') }}"
+openstack_helm_endpoints_nova_mariadb_password: "{{ undef(hint='You must specify a Nova MariaDB password') }}"
+openstack_helm_endpoints_nova_rabbitmq_password: "{{ undef(hint='You must specify a Nova RabbitMQ password') }}"
+
+# Ironic
+openstack_helm_endpoints_ironic_api_host: "{{ undef(hint='You must specify an Ironic API hostname') }}"
+openstack_helm_endpoints_ironic_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_ironic_keystone_password: "{{ undef(hint='You must specify an Ironic Keystone password') }}"
+openstack_helm_endpoints_ironic_mariadb_password: "{{ undef(hint='You must specify an Ironic MariaDB password') }}"
+openstack_helm_endpoints_ironic_rabbitmq_password: "{{ undef(hint='You must specify an Ironic RabbitMQ password') }}"
+
+# Designate
+openstack_helm_endpoints_designate_api_host: "{{ undef(hint='You must specify a Designate API hostname') }}"
+openstack_helm_endpoints_designate_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_designate_keystone_password: "{{ undef(hint='You must specify a Designate Keystone password') }}"
+openstack_helm_endpoints_designate_mariadb_password: "{{ undef(hint='You must specify a Designate MariaDB password') }}"
+openstack_helm_endpoints_designate_rabbitmq_password: "{{ undef(hint='You must specify a Designate RabbitMQ password') }}"
+
+# Octavia
+openstack_helm_endpoints_octavia_api_host: "{{ undef(hint='You must specify an Octavia API hostname') }}"
+openstack_helm_endpoints_octavia_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_octavia_keystone_password: "{{ undef(hint='You must specify an Octavia Keystone password') }}"
+openstack_helm_endpoints_octavia_mariadb_password: "{{ undef(hint='You must specify an Octavia MariaDB password') }}"
+openstack_helm_endpoints_octavia_rabbitmq_password: "{{ undef(hint='You must specify an Octavia RabbitMQ password') }}"
+
+# Heat
+openstack_helm_endpoints_heat_api_host: "{{ undef(hint='You must specify a Heat API hostname') }}"
+openstack_helm_endpoints_heat_region_name: "{{ openstack_helm_endpoints_region_name }}"
+openstack_helm_endpoints_heat_keystone_password: "{{ undef(hint='You must specify a Heat Keystone password') }}"
+openstack_helm_endpoints_heat_trustee_keystone_password: "{{ undef(hint='You must specify a Heat trustee Keystone password') }}"
+openstack_helm_endpoints_heat_stack_user_keystone_password: "{{ undef(hint='You must specify a Heat stack user Keystone password') }}"
+openstack_helm_endpoints_heat_mariadb_password: "{{ undef(hint='You must specify a Heat MariaDB password') }}"
+openstack_helm_endpoints_heat_rabbitmq_password: "{{ undef(hint='You must specify a Heat RabbitMQ password') }}"
+openstack_helm_endpoints_heat_cfn_api_host: "{{ undef(hint='You must specify a Heat CloudFormation API hostname') }}"
+
+# Horizon
+openstack_helm_endpoints_horizon_api_host: "{{ undef(hint='You must specify a Horizon API hostname') }}"
+openstack_helm_endpoints_horizon_mariadb_password: "{{ undef(hint='You must specify a Horizon MariaDB password') }}"
diff --git a/roles/openstack_helm_endpoints/tasks/main.yml b/roles/openstack_helm_endpoints/tasks/main.yml
new file mode 100644
index 0000000..a73b6f9
--- /dev/null
+++ b/roles/openstack_helm_endpoints/tasks/main.yml
@@ -0,0 +1,65 @@
+# 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: Get Helm values if chart is provided
+ block:
+ - name: Get the default values for the Helm chart
+ ansible.builtin.shell: helm show values {{ openstack_helm_endpoints_repo_name }}/{{ openstack_helm_endpoints_chart }}
+ changed_when: false
+ register: _helm_show_values
+
+ - name: Retrieve list of all the needed endpoints
+ ansible.builtin.set_fact:
+ openstack_helm_endpoints_list: "{{ _helm_show_values.stdout | from_yaml | community.general.json_query('keys(endpoints)') | difference(_openstack_helm_endpoints_ignore) }}"
+ when:
+ - openstack_helm_endpoints_list is not defined or openstack_helm_endpoints_list == None
+
+# NOTE(mnaser): Since we deploy the database using the operator and we let it
+# generate the root password, we look it up if the fact has not
+# been cached from a previous run.
+- name: Append endpoints for "oslo_db"
+ block:
+ - name: Grab Percona XtraDB cluster secret
+ kubernetes.core.k8s_info:
+ api_version: v1
+ kind: Secret
+ name: percona-xtradb
+ namespace: openstack
+ register: _openstack_helm_endpoints_oslo_db_secret
+
+ - name: Cache fact with Percona XtraDB password
+ ansible.builtin.set_fact:
+ openstack_helm_endpoints_maridb_admin_password: "{{ _openstack_helm_endpoints_oslo_db_secret.resources[0]['data']['root'] | b64decode }}"
+ when:
+ - '"oslo_db" in openstack_helm_endpoints_list'
+ - openstack_helm_endpoints_maridb_admin_password is not defined
+
+- name: Reset value for OpenStack_Helm endpoints
+ ansible.builtin.set_fact:
+ openstack_helm_endpoints: "{{ openstack_helm_endpoints_config }}"
+
+- name: Generate OpenStack-Helm endpoints
+ ansible.builtin.set_fact:
+ openstack_helm_endpoints: |
+ {{ openstack_helm_endpoints | combine(lookup('vars', '_openstack_helm_endpoints_' + service), recursive=True) }}
+ loop: "{{ openstack_helm_endpoints_list }}"
+ loop_control:
+ loop_var: service
+
+# NOTE(mnaser): Since we use `openstack_helm_endpoints_list` to ensure that we
+# have a common entry for endpoints and stay DRY, we need to
+# reset the fact so it works for follow-up requests.
+- name: Clean-up facts
+ ansible.builtin.set_fact:
+ openstack_helm_endpoints_list:
diff --git a/roles/openstack_helm_endpoints/vars/main.yml b/roles/openstack_helm_endpoints/vars/main.yml
new file mode 100644
index 0000000..eb46051
--- /dev/null
+++ b/roles/openstack_helm_endpoints/vars/main.yml
@@ -0,0 +1,378 @@
+# 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_endpoints_ignore:
+ - ceph_object_store
+ - cloudwatch
+ - cluster_domain_suffix
+ - compute_spice_proxy
+ - fluentd
+ - ingress
+ - kube_dns
+ - ldap
+ - local_image_registry
+ - monitoring
+ - object_store
+ - prometheus_rabbitmq_exporter
+
+_openstack_helm_endpoints_oslo_db:
+ oslo_db:
+ auth:
+ admin:
+ password: "{{ openstack_helm_endpoints_maridb_admin_password }}"
+ hosts:
+ default: percona-xtradb-haproxy
+
+_openstack_helm_endpoints_oslo_messaging:
+ oslo_messaging:
+ auth:
+ erlang_cookie: "{{ openstack_helm_endpoints_rabbitmq_erlang_cookie }}"
+ user:
+ password: "{{ openstack_helm_endpoints_rabbitmq_admin_password }}"
+ # NOTE(mnaser): The following is not actually used by the chart, however,
+ # since we are actually doing dynamic lookups to generate
+ # endpoints, we add it here.
+ admin:
+ password: "{{ openstack_helm_endpoints_rabbitmq_admin_password }}"
+ statefulset:
+ replicas: 3
+
+_openstack_helm_endpoints_oslo_cache:
+ oslo_cache:
+ auth:
+ memcache_secret_key: "{{ openstack_helm_endpoints_memcached_secret_key }}"
+
+_openstack_helm_endpoints_identity:
+ identity:
+ auth:
+ admin:
+ region_name: "{{ openstack_helm_endpoints_keystone_region_name }}"
+ username: "admin-{{ openstack_helm_endpoints_keystone_region_name }}"
+ password: "{{ openstack_helm_endpoints_keystone_admin_password }}"
+ hosts:
+ default: keystone-api
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_keystone_api_host }}"
+ port:
+ api:
+ default: 5000
+ public: 443
+ oslo_db:
+ auth:
+ keystone:
+ password: "{{ openstack_helm_endpoints_keystone_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ keystone:
+ password: "{{ openstack_helm_endpoints_keystone_rabbitmq_password }}"
+
+_openstack_helm_endpoints_image:
+ identity:
+ auth:
+ glance:
+ region_name: "{{ openstack_helm_endpoints_glance_region_name }}"
+ username: "glance-{{ openstack_helm_endpoints_glance_region_name }}"
+ password: "{{ openstack_helm_endpoints_glance_keystone_password }}"
+ image:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_glance_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ glance:
+ password: "{{ openstack_helm_endpoints_glance_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ glance:
+ password: "{{ openstack_helm_endpoints_glance_rabbitmq_password }}"
+
+_openstack_helm_endpoints_volumev3:
+ identity:
+ auth:
+ cinder:
+ region_name: "{{ openstack_helm_endpoints_cinder_region_name }}"
+ username: "cinder-{{ openstack_helm_endpoints_cinder_region_name }}"
+ password: "{{ openstack_helm_endpoints_cinder_keystone_password }}"
+ volumev3:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_cinder_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ cinder:
+ password: "{{ openstack_helm_endpoints_cinder_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ cinder:
+ password: "{{ openstack_helm_endpoints_cinder_rabbitmq_password }}"
+
+_openstack_helm_endpoints_placement:
+ identity:
+ auth:
+ placement:
+ region_name: "{{ openstack_helm_endpoints_placement_region_name }}"
+ username: "placement-{{ openstack_helm_endpoints_placement_region_name }}"
+ password: "{{ openstack_helm_endpoints_placement_keystone_password }}"
+ oslo_db:
+ auth:
+ placement:
+ password: "{{ openstack_helm_endpoints_placement_mariadb_password }}"
+ placement:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_placement_api_host }}"
+ port:
+ api:
+ public: 443
+
+_openstack_helm_endpoints_network:
+ identity:
+ auth:
+ neutron:
+ region_name: "{{ openstack_helm_endpoints_neutron_region_name }}"
+ username: "neutron-{{ openstack_helm_endpoints_neutron_region_name }}"
+ password: "{{ openstack_helm_endpoints_neutron_keystone_password }}"
+ network:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_neutron_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ neutron:
+ password: "{{ openstack_helm_endpoints_neutron_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ neutron:
+ password: "{{ openstack_helm_endpoints_neutron_rabbitmq_password }}"
+
+_openstack_helm_endpoints_compute:
+ identity:
+ auth:
+ nova:
+ region_name: "{{ openstack_helm_endpoints_nova_region_name }}"
+ username: "nova-{{ openstack_helm_endpoints_nova_region_name }}"
+ password: "{{ openstack_helm_endpoints_nova_keystone_password }}"
+ compute:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_nova_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ nova:
+ password: "{{ openstack_helm_endpoints_nova_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ nova:
+ password: "{{ openstack_helm_endpoints_nova_rabbitmq_password }}"
+
+_openstack_helm_endpoints_oslo_db_api:
+ oslo_db_api:
+ auth:
+ admin:
+ password: "{{ openstack_helm_endpoints_maridb_admin_password }}"
+ nova:
+ password: "{{ openstack_helm_endpoints_nova_mariadb_password }}"
+ hosts:
+ default: percona-xtradb-haproxy
+
+_openstack_helm_endpoints_oslo_db_cell0:
+ oslo_db_cell0:
+ auth:
+ admin:
+ password: "{{ openstack_helm_endpoints_maridb_admin_password }}"
+ nova:
+ password: "{{ openstack_helm_endpoints_nova_mariadb_password }}"
+ hosts:
+ default: percona-xtradb-haproxy
+
+_openstack_helm_endpoints_compute_metadata:
+ compute_metadata:
+ secret: "{{ openstack_helm_endpoints_neutron_metadata_secret }}"
+ hosts:
+ public: nova-metadata
+ port:
+ metadata:
+ public: 8775
+
+_openstack_helm_endpoints_compute_novnc_proxy:
+ compute_novnc_proxy:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_nova_novnc_host }}"
+ port:
+ novnc_proxy:
+ public: 443
+
+_openstack_helm_endpoints_baremetal:
+ identity:
+ auth:
+ ironic:
+ region_name: "{{ openstack_helm_endpoints_ironic_region_name }}"
+ username: "ironic-{{ openstack_helm_endpoints_ironic_region_name }}"
+ password: "{{ openstack_helm_endpoints_ironic_keystone_password }}"
+ baremetal:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_ironic_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ ironic:
+ password: "{{ openstack_helm_endpoints_ironic_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ ironic:
+ password: "{{ openstack_helm_endpoints_ironic_rabbitmq_password }}"
+
+_openstack_helm_endpoints_dns:
+ identity:
+ auth:
+ designate:
+ region_name: "{{ openstack_helm_endpoints_designate_region_name }}"
+ username: "desigante-{{ openstack_helm_endpoints_designate_region_name }}"
+ password: "{{ openstack_helm_endpoints_designate_keystone_password }}"
+ dns:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_designate_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ designate:
+ password: "{{ openstack_helm_endpoints_designate_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ designate:
+ password: "{{ openstack_helm_endpoints_designate_rabbitmq_password }}"
+
+_openstack_helm_endpoints_load_balancer:
+ identity:
+ auth:
+ octavia:
+ region_name: "{{ openstack_helm_endpoints_octavia_region_name }}"
+ username: "octavia-{{ openstack_helm_endpoints_octavia_region_name }}"
+ password: "{{ openstack_helm_endpoints_octavia_keystone_password }}"
+ load_balancer:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_octavia_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ octavia:
+ password: "{{ openstack_helm_endpoints_octavia_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ octavia:
+ password: "{{ openstack_helm_endpoints_octavia_rabbitmq_password }}"
+
+_openstack_helm_endpoints_cloudformation:
+ cloudformation:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_heat_cfn_api_host }}"
+ port:
+ api:
+ public: 443
+
+_openstack_helm_endpoints_orchestration:
+ identity:
+ auth:
+ heat:
+ region_name: "{{ openstack_helm_endpoints_heat_region_name }}"
+ username: "heat-{{ openstack_helm_endpoints_heat_region_name }}"
+ password: "{{ openstack_helm_endpoints_heat_keystone_password }}"
+ heat_trustee:
+ region_name: "{{ openstack_helm_endpoints_heat_region_name }}"
+ username: "heat-trustee-{{ openstack_helm_endpoints_heat_region_name }}"
+ password: "{{ openstack_helm_endpoints_heat_trustee_keystone_password }}"
+ heat_stack_user:
+ region_name: "{{ openstack_helm_endpoints_heat_region_name }}"
+ username: "heat-stack-user-{{ openstack_helm_endpoints_heat_region_name }}"
+ password: "{{ openstack_helm_endpoints_heat_stack_user_keystone_password }}"
+ path:
+ public: /v3
+ orchestration:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_heat_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ heat:
+ password: "{{ openstack_helm_endpoints_heat_mariadb_password }}"
+ oslo_messaging:
+ auth:
+ heat:
+ password: "{{ openstack_helm_endpoints_heat_rabbitmq_password }}"
+
+_openstack_helm_endpoints_dashboard:
+ dashboard:
+ scheme:
+ public: https
+ host_fqdn_override:
+ public:
+ host: "{{ openstack_helm_endpoints_horizon_api_host }}"
+ port:
+ api:
+ public: 443
+ oslo_db:
+ auth:
+ horizon:
+ password: "{{ openstack_helm_endpoints_horizon_mariadb_password }}"
diff --git a/roles/openstack_helm_glance/defaults/main.yml b/roles/openstack_helm_glance/defaults/main.yml
new file mode 100644
index 0000000..bfb6e83
--- /dev/null
+++ b/roles/openstack_helm_glance/defaults/main.yml
@@ -0,0 +1,23 @@
+# 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_glance_chart_repo_name: openstack-helm
+openstack_helm_glance_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_glance_chart_name: glance
+
+openstack_helm_glance_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_glance_image_tag: 22.1.1.dev2-1
+openstack_helm_glance_heat_image_tag: wallaby
+
+openstack_helm_glance_values: {}
diff --git a/roles/openstack_helm_glance/meta/main.yml b/roles/openstack_helm_glance/meta/main.yml
new file mode 100644
index 0000000..a7eaa64
--- /dev/null
+++ b/roles/openstack_helm_glance/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_glance_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_glance_chart_repo_url }}"
diff --git a/roles/openstack_helm_glance/tasks/main.yml b/roles/openstack_helm_glance/tasks/main.yml
new file mode 100644
index 0000000..0abdb87
--- /dev/null
+++ b/roles/openstack_helm_glance/tasks/main.yml
@@ -0,0 +1,41 @@
+# 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_glance_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_glance_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_glance_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_glance_chart_name }}"
+ chart_ref: "{{ openstack_helm_glance_chart_repo_name }}/{{ openstack_helm_glance_chart_name }}"
+ chart_version: 0.2.10
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_glance_values | combine(openstack_helm_glance_values, recursive=True) }}"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: image
+ openstack_helm_ingress_service_name: glance-api
+ openstack_helm_ingress_service_port: 9292
+ openstack_helm_ingress_annotations:
+ nginx.ingress.kubernetes.io/proxy-body-size: "0"
+ nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
diff --git a/roles/openstack_helm_glance/vars/main.yml b/roles/openstack_helm_glance/vars/main.yml
new file mode 100644
index 0000000..41b8016
--- /dev/null
+++ b/roles/openstack_helm_glance/vars/main.yml
@@ -0,0 +1,51 @@
+# 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_glance_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ storage: rbd
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_glance_image_repository }}/heat:{{ openstack_helm_glance_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_glance_image_repository }}/heat:{{ openstack_helm_glance_heat_image_tag }}"
+ db_init: "{{ openstack_helm_glance_image_repository }}/heat:{{ openstack_helm_glance_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_glance_image_repository }}/kubernetes-entrypoint:latest"
+ glance_api: "{{ openstack_helm_glance_image_repository }}/glance:{{ openstack_helm_glance_image_tag }}"
+ glance_db_sync: "{{ openstack_helm_glance_image_repository }}/glance:{{ openstack_helm_glance_image_tag }}"
+ glance_metadefs_load: "{{ openstack_helm_glance_image_repository }}/glance:{{ openstack_helm_glance_image_tag }}"
+ glance_registry: "{{ openstack_helm_glance_image_repository }}/glance:{{ openstack_helm_glance_image_tag }}"
+ glance_storage_init: "{{ openstack_helm_glance_image_repository }}/glance:{{ openstack_helm_glance_image_tag }}"
+ ks_endpoints: "{{ openstack_helm_glance_image_repository }}/heat:{{ openstack_helm_glance_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_glance_image_repository }}/heat:{{ openstack_helm_glance_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_glance_image_repository }}/heat:{{ openstack_helm_glance_heat_image_tag }}"
+ rabbit_init: "{{ openstack_helm_glance_image_repository }}/rabbitmq:3.8.23-management"
+ bootstrap:
+ enabled: false
+ pod:
+ replicas:
+ api: 3
+ conf:
+ glance:
+ DEFAULT:
+ log_config_append: null
+ show_image_direct_url: true
+ show_multiple_locations: true
+ enable_import_methods: "[]"
+ cors:
+ allowed_origins: "*"
+ image_formats:
+ disk_formats: "qcow2,raw"
+ manifests:
+ ingress_api: false
+ service_ingress_api: false
diff --git a/roles/openstack_helm_heat/defaults/main.yml b/roles/openstack_helm_heat/defaults/main.yml
new file mode 100644
index 0000000..3ca6123
--- /dev/null
+++ b/roles/openstack_helm_heat/defaults/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.
+
+openstack_helm_heat_chart_repo_name: openstack-helm
+openstack_helm_heat_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_heat_chart_name: heat
+
+openstack_helm_heat_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_heat_image_tag: 16.0.1.dev16
+
+openstack_helm_heat_auth_encryption_key: "{{ undef(hint='You must specifiy an encryption key for Heat.') }}"
+
+openstack_helm_heat_diff: false
+openstack_helm_heat_migrate_from_mariadb: false
+
+openstack_helm_heat_values: {}
diff --git a/roles/openstack_helm_heat/meta/main.yml b/roles/openstack_helm_heat/meta/main.yml
new file mode 100644
index 0000000..3dfc746
--- /dev/null
+++ b/roles/openstack_helm_heat/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_heat_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_heat_chart_repo_url }}"
diff --git a/roles/openstack_helm_heat/tasks/main.yml b/roles/openstack_helm_heat/tasks/main.yml
new file mode 100644
index 0000000..7390441
--- /dev/null
+++ b/roles/openstack_helm_heat/tasks/main.yml
@@ -0,0 +1,74 @@
+# 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_heat_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_heat_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_heat_chart_name }}"
+
+- name: Generate Helm values comparison
+ ansible.builtin.include_role:
+ name: helm_diff
+ vars:
+ helm_diff_release_name: "{{ openstack_helm_heat_chart_name }}"
+ helm_diff_release_namespace: openstack
+ helm_diff_values: "{{ _openstack_helm_heat_values }}"
+ when:
+ - openstack_helm_heat_diff | bool
+
+- name: Migrate database from MariaDB to Percona XtraDB Cluster
+ ansible.builtin.include_role:
+ name: openstack_helm_migrate_to_percona_xtradb_cluster
+ vars:
+ openstack_helm_migrate_to_percona_xtradb_cluster_release_name: "{{ openstack_helm_heat_chart_name }}"
+ openstack_helm_migrate_to_percona_xtradb_cluster_release_namespace: openstack
+ openstack_helm_migrate_to_percona_xtradb_cluster_databases:
+ - heat
+ openstack_helm_migrate_to_percona_xtradb_cluster_services:
+ - kind: Deployment
+ name: heat-api
+ - kind: Deployment
+ name: heat-cfn
+ - kind: Deployment
+ name: heat-engine
+ when:
+ - openstack_helm_heat_migrate_from_mariadb | bool
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_heat_chart_name }}"
+ chart_ref: "{{ openstack_helm_heat_chart_repo_name }}/{{ openstack_helm_heat_chart_name }}"
+ chart_version: 0.2.8
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_heat_values }}"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: orchestration
+ openstack_helm_ingress_service_name: heat-api
+ openstack_helm_ingress_service_port: 8004
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: cloudformation
+ openstack_helm_ingress_service_name: heat-cfn
+ openstack_helm_ingress_service_port: 8000
diff --git a/roles/openstack_helm_heat/vars/main.yml b/roles/openstack_helm_heat/vars/main.yml
new file mode 100644
index 0000000..abec726
--- /dev/null
+++ b/roles/openstack_helm_heat/vars/main.yml
@@ -0,0 +1,54 @@
+# 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_heat_values: "{{ __openstack_helm_heat_values | combine(openstack_helm_heat_values, recursive=True) }}"
+__openstack_helm_heat_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ db_init: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_heat_image_repository }}/kubernetes-entrypoint:latest"
+ heat_api: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ heat_cfn: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ heat_cloudwatch: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ heat_db_sync: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ heat_engine_cleaner: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ heat_engine: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ heat_purge_deleted: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ ks_endpoints: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_heat_image_repository }}/heat:{{ openstack_helm_heat_image_tag }}"
+ rabbit_init: "{{ openstack_helm_heat_image_repository }}/rabbitmq:3.8.23-management"
+ pod:
+ replicas:
+ api: 3
+ cfn: 3
+ cloudwatch: 3
+ engine: 3
+ conf:
+ heat:
+ DEFAULT:
+ auth_encryption_key: "{{ openstack_helm_heat_auth_encryption_key }}"
+ log_config_append: null
+ region_name_for_services: "{{ openstack_helm_endpoints['identity']['auth']['heat']['region_name'] }}"
+ server_keystone_endpoint_type: public
+ clients_keystone:
+ endpoint_type: publicURL
+ manifests:
+ ingress_api: false
+ ingress_cfn: false
+ service_ingress_api: false
+ service_ingress_cfn: false
diff --git a/roles/openstack_helm_horizon/defaults/main.yml b/roles/openstack_helm_horizon/defaults/main.yml
new file mode 100644
index 0000000..ba6c691
--- /dev/null
+++ b/roles/openstack_helm_horizon/defaults/main.yml
@@ -0,0 +1,23 @@
+# 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_horizon_chart_repo_name: openstack-helm
+openstack_helm_horizon_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_horizon_chart_name: horizon
+
+openstack_helm_horizon_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_horizon_image_tag: 19.2.1.dev13
+openstack_helm_horizon_heat_image_tag: wallaby
+
+openstack_helm_horizon_values: {}
diff --git a/roles/openstack_helm_horizon/files/50-monasca-ui-settings.py b/roles/openstack_helm_horizon/files/50-monasca-ui-settings.py
new file mode 100644
index 0000000..28b4a99
--- /dev/null
+++ b/roles/openstack_helm_horizon/files/50-monasca-ui-settings.py
@@ -0,0 +1,56 @@
+from django.conf import settings
+from django.utils.translation import ugettext_lazy as _
+
+# Service group names (global across all projects):
+MONITORING_SERVICES_GROUPS = [
+ {'name': _('OpenStack Services'), 'groupBy': 'service'},
+ {'name': _('Servers'), 'groupBy': 'hostname'}
+]
+
+# Services being monitored
+MONITORING_SERVICES = getattr(
+ settings,
+ 'MONITORING_SERVICES_GROUPS',
+ MONITORING_SERVICES_GROUPS
+)
+
+MONITORING_SERVICE_VERSION = getattr(
+ settings, 'MONITORING_SERVICE_VERSION', '2_0'
+)
+MONITORING_SERVICE_TYPE = getattr(
+ settings, 'MONITORING_SERVICE_TYPE', 'monitoring'
+)
+MONITORING_ENDPOINT_TYPE = getattr(
+ # NOTE(trebskit) # will default to OPENSTACK_ENDPOINT_TYPE
+ settings, 'MONITORING_ENDPOINT_TYPE', None
+)
+
+# Grafana button titles/file names (global across all projects):
+# GRAFANA_LINKS = [{"raw": True, "path": "monasca-dashboard", "title": "Sub page1"}]
+GRAFANA_LINKS = []
+DASHBOARDS = getattr(settings, 'GRAFANA_LINKS', GRAFANA_LINKS)
+
+GRAFANA_URL = {"regionOne": "/grafana"}
+
+SHOW_GRAFANA_HOME = getattr(settings, 'SHOW_GRAFANA_HOME', True)
+
+ENABLE_LOG_MANAGEMENT_BUTTON = getattr(
+ settings, 'ENABLE_LOG_MANAGEMENT_BUTTON', False)
+ENABLE_EVENT_MANAGEMENT_BUTTON = getattr(
+ settings, 'ENABLE_EVENT_MANAGEMENT_BUTTON', False)
+
+KIBANA_POLICY_RULE = getattr(settings, 'KIBANA_POLICY_RULE',
+ 'monitoring:kibana_access')
+KIBANA_POLICY_SCOPE = getattr(settings, 'KIBANA_POLICY_SCOPE',
+ 'monitoring')
+KIBANA_HOST = getattr(settings, 'KIBANA_HOST',
+ 'http://192.168.10.6:5601/')
+
+OPENSTACK_SSL_NO_VERIFY = getattr(
+ settings, 'OPENSTACK_SSL_NO_VERIFY', False)
+OPENSTACK_SSL_CACERT = getattr(
+ settings, 'OPENSTACK_SSL_CACERT', None)
+
+POLICY_FILES = getattr(settings, 'POLICY_FILES', {})
+POLICY_FILES.update({'monitoring': 'monitoring_policy.json', }) # noqa
+setattr(settings, 'POLICY_FILES', POLICY_FILES)
diff --git a/roles/openstack_helm_horizon/meta/main.yml b/roles/openstack_helm_horizon/meta/main.yml
new file mode 100644
index 0000000..8027f7c
--- /dev/null
+++ b/roles/openstack_helm_horizon/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_horizon_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_horizon_chart_repo_url }}"
diff --git a/roles/openstack_helm_horizon/tasks/main.yml b/roles/openstack_helm_horizon/tasks/main.yml
new file mode 100644
index 0000000..58bea45
--- /dev/null
+++ b/roles/openstack_helm_horizon/tasks/main.yml
@@ -0,0 +1,46 @@
+# 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_horizon_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_horizon_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_horizon_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_horizon_chart_name }}"
+ chart_ref: "{{ openstack_helm_horizon_chart_repo_name }}/{{ openstack_helm_horizon_chart_name }}"
+ chart_version: 0.2.16
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_horizon_values | combine(openstack_helm_horizon_values, recursive=True) }}"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: dashboard
+ openstack_helm_ingress_service_name: horizon-int
+ openstack_helm_ingress_service_port: 80
+ openstack_helm_ingress_paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: grafana
+ port:
+ number: 80
diff --git a/roles/openstack_helm_horizon/vars/main.yml b/roles/openstack_helm_horizon/vars/main.yml
new file mode 100644
index 0000000..b63c869
--- /dev/null
+++ b/roles/openstack_helm_horizon/vars/main.yml
@@ -0,0 +1,60 @@
+# 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_horizon_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_horizon_image_repository }}/heat:{{ openstack_helm_horizon_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_horizon_image_repository }}/heat:{{ openstack_helm_horizon_heat_image_tag }}"
+ db_init: "{{ openstack_helm_horizon_image_repository }}/heat:{{ openstack_helm_horizon_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_horizon_image_repository }}/kubernetes-entrypoint:latest"
+ ks_endpoints: "{{ openstack_helm_horizon_image_repository }}/heat:{{ openstack_helm_horizon_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_horizon_image_repository }}/heat:{{ openstack_helm_horizon_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_horizon_image_repository }}/heat:{{ openstack_helm_horizon_heat_image_tag }}"
+ horizon_db_sync: "{{ openstack_helm_horizon_image_repository }}/horizon:{{ openstack_helm_horizon_image_tag }}"
+ horizon: "{{ openstack_helm_horizon_image_repository }}/horizon:{{ openstack_helm_horizon_image_tag }}"
+ rabbit_init: "{{ openstack_helm_horizon_image_repository }}/rabbitmq:3.8.23-management"
+ pod:
+ replicas:
+ server: 3
+ conf:
+ horizon:
+ local_settings:
+ config:
+ secure_proxy_ssl_header: "True"
+ horizon_images_upload_mode: direct
+ openstack_enable_password_retrieve: "True"
+ raw:
+ WEBSSO_KEYSTONE_URL: "https://{{ openstack_helm_endpoints['identity']['scheme']['public'] }}://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}/v3"
+ local_settings_d:
+ _50_monasca_ui_settings: "{{ lookup('file', '50-monasca-ui-settings.py') }}"
+ extra_panels:
+ - designatedashboard
+ - heat_dashboard
+ - ironic_ui
+ - magnum_ui
+ - monitoring
+ - neutron_vpnaas_dashboard
+ - octavia_dashboard
+ - senlin_dashboard
+ policy:
+ monitoring:
+ default: "@"
+ monasca_user_role: role:monasca-user
+ monitoring:monitoring: rule:monasca_user_role
+ monitoring:kibana_access: rule:monasca_user_role
+ manifests:
+ ingress_api: false
+ service_ingress_api: false
diff --git a/roles/openstack_helm_infra_ceph_provisioners/defaults/main.yml b/roles/openstack_helm_infra_ceph_provisioners/defaults/main.yml
new file mode 100644
index 0000000..f450a53
--- /dev/null
+++ b/roles/openstack_helm_infra_ceph_provisioners/defaults/main.yml
@@ -0,0 +1,23 @@
+# 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_infra_ceph_provisioners_chart_repo_name: openstack-helm-infra
+openstack_helm_infra_ceph_provisioners_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm-infra/
+openstack_helm_infra_ceph_provisioners_chart_name: ceph-provisioners
+
+openstack_helm_infra_ceph_provisioners_ceph_monitors: "{{ _ceph_csi_rbd_helm_info.status['values']['csiConfig'][0]['monitors'] }}"
+openstack_helm_infra_ceph_provisioners_ceph_fsid: "{{ _ceph_csi_rbd_helm_info.status['values']['csiConfig'][0]['clusterID'] }}"
+
+openstack_helm_infra_ceph_provisioners_ceph_public_network: "{{ ceph_mon_public_network }}"
+openstack_helm_infra_ceph_provisioners_ceph_cluster_network: "{{ openstack_helm_infra_ceph_provisioners_ceph_public_network }}"
diff --git a/roles/openstack_helm_infra_ceph_provisioners/meta/main.yml b/roles/openstack_helm_infra_ceph_provisioners/meta/main.yml
new file mode 100644
index 0000000..7f7df71
--- /dev/null
+++ b/roles/openstack_helm_infra_ceph_provisioners/meta/main.yml
@@ -0,0 +1,20 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_infra_ceph_provisioners_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_infra_ceph_provisioners_chart_repo_url }}"
+ - ceph_csi_rbd
diff --git a/roles/openstack_helm_infra_ceph_provisioners/tasks/main.yml b/roles/openstack_helm_infra_ceph_provisioners/tasks/main.yml
new file mode 100644
index 0000000..b43c3b1
--- /dev/null
+++ b/roles/openstack_helm_infra_ceph_provisioners/tasks/main.yml
@@ -0,0 +1,128 @@
+# 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: Retrieve Helm values for "ceph-csi-rbd"
+ kubernetes.core.helm_info:
+ name: ceph-csi-rbd
+ release_namespace: kube-system
+ register: _ceph_csi_rbd_helm_info
+
+- name: Create Ceph service
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Service
+ metadata:
+ name: ceph-mon
+ namespace: openstack
+ labels:
+ application: ceph
+ spec:
+ clusterIP: None
+ ports:
+ - name: mon
+ port: 6789
+ targetPort: 6789
+ - name: mon-msgr2
+ port: 3300
+ targetPort: 3300
+ - name: metrics
+ port: 9283
+ targetPort: 9283
+
+- name: Generate Ceph endpoint list
+ ansible.builtin.set_fact:
+ _openstack_helm_infra_ceph_provisioners_ceph_monitors: |
+ {{
+ _openstack_helm_infra_ceph_provisioners_ceph_monitors | default([]) +
+ [{'ip': item}]
+ }}
+ loop: "{{ openstack_helm_infra_ceph_provisioners_ceph_monitors }}"
+
+- name: Create Ceph endpoints
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Endpoints
+ metadata:
+ name: ceph-mon
+ namespace: openstack
+ labels:
+ application: ceph
+ subsets:
+ - addresses: "{{ _openstack_helm_infra_ceph_provisioners_ceph_monitors }}"
+ ports:
+ - name: mon
+ port: 6789
+ protocol: TCP
+ - name: mon-msgr2
+ port: 3300
+ protocol: TCP
+ - name: metrics
+ port: 9283
+ protocol: TCP
+
+- name: Retrieve client.admin keyring
+ vexxhost.atmosphere.ceph_key:
+ name: client.admin
+ state: info
+ output_format: json
+ register: _openstack_helm_infra_ceph_provisioners_ceph_key
+
+- name: Parse client.admin keyring
+ ansible.builtin.set_fact:
+ _openstack_helm_infra_ceph_provisioners_keyring: "{{ _openstack_helm_infra_ceph_provisioners_ceph_key.stdout | from_json | first }}"
+
+- name: Create "pvc-ceph-client-key" secret
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Secret
+ type: kubernetes.io/rbd
+ metadata:
+ name: pvc-ceph-client-key
+ namespace: openstack
+ labels:
+ application: ceph
+ stringData:
+ key: "{{ _openstack_helm_infra_ceph_provisioners_keyring.key }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_infra_ceph_provisioners_chart_name }}"
+ chart_ref: "{{ openstack_helm_infra_ceph_provisioners_chart_repo_name }}/{{ openstack_helm_infra_ceph_provisioners_chart_name }}"
+ chart_version: 0.1.17
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ network:
+ public: "{{ openstack_helm_infra_ceph_provisioners_ceph_public_network }}"
+ cluster: "{{ openstack_helm_infra_ceph_provisioners_ceph_cluster_network }}"
+ conf:
+ ceph:
+ global:
+ fsid: "{{ openstack_helm_infra_ceph_provisioners_ceph_fsid }}"
+ manifests:
+ configmap_bin: false
+ configmap_bin_common: false
+ deployment_rbd_provisioner: false
+ deployment_csi_rbd_provisioner: false
+ deployment_cephfs_provisioner: false
+ job_cephfs_client_key: false
+ job_namespace_client_key_cleaner: false
+ job_namespace_client_key: false
+ storageclass: false
diff --git a/roles/openstack_helm_infra_libvirt/defaults/main.yml b/roles/openstack_helm_infra_libvirt/defaults/main.yml
new file mode 100644
index 0000000..c2c4511
--- /dev/null
+++ b/roles/openstack_helm_infra_libvirt/defaults/main.yml
@@ -0,0 +1,22 @@
+# 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_infra_libvirt_chart_repo_name: openstack-helm-infra
+openstack_helm_infra_libvirt_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm-infra/
+openstack_helm_infra_libvirt_chart_name: libvirt
+
+openstack_helm_infra_libvirt_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_infra_libvirt_image_tag: wallaby
+
+openstack_helm_infra_libvirt_values: {}
diff --git a/roles/openstack_helm_infra_libvirt/meta/main.yml b/roles/openstack_helm_infra_libvirt/meta/main.yml
new file mode 100644
index 0000000..67fb174
--- /dev/null
+++ b/roles/openstack_helm_infra_libvirt/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_infra_libvirt_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_infra_libvirt_chart_repo_url }}"
diff --git a/roles/openstack_helm_infra_libvirt/tasks/main.yml b/roles/openstack_helm_infra_libvirt/tasks/main.yml
new file mode 100644
index 0000000..46df5d1
--- /dev/null
+++ b/roles/openstack_helm_infra_libvirt/tasks/main.yml
@@ -0,0 +1,30 @@
+# 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_infra_libvirt_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_infra_libvirt_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_infra_libvirt_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_infra_libvirt_chart_name }}"
+ chart_ref: "{{ openstack_helm_infra_libvirt_chart_repo_name }}/{{ openstack_helm_infra_libvirt_chart_name }}"
+ chart_version: 0.1.8
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_infra_libvirt_values | combine(openstack_helm_infra_libvirt_values, recursive=True) }}"
diff --git a/roles/openstack_helm_infra_libvirt/vars/main.yml b/roles/openstack_helm_infra_libvirt/vars/main.yml
new file mode 100644
index 0000000..f79b2a8
--- /dev/null
+++ b/roles/openstack_helm_infra_libvirt/vars/main.yml
@@ -0,0 +1,24 @@
+# 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_infra_libvirt_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ ceph_config_helper: "{{ openstack_helm_infra_libvirt_image_repository }}/libvirt:{{ openstack_helm_infra_libvirt_image_tag }}"
+ dep_check: "{{ openstack_helm_infra_libvirt_image_repository }}/kubernetes-entrypoint:latest"
+ libvirt: "{{ openstack_helm_infra_libvirt_image_repository }}/libvirt:{{ openstack_helm_infra_libvirt_image_tag }}"
+ conf:
+ libvirt:
+ listen_addr: 0.0.0.0
diff --git a/roles/openstack_helm_infra_memcached/defaults/main.yml b/roles/openstack_helm_infra_memcached/defaults/main.yml
new file mode 100644
index 0000000..23a09da
--- /dev/null
+++ b/roles/openstack_helm_infra_memcached/defaults/main.yml
@@ -0,0 +1,20 @@
+# 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_infra_memcached_chart_repo_name: openstack-helm-infra
+openstack_helm_infra_memcached_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm-infra/
+openstack_helm_infra_memcached_chart_name: memcached
+
+openstack_helm_infra_memcached_diff: false
+openstack_helm_infra_memcached_values: {}
diff --git a/roles/openstack_helm_infra_memcached/meta/main.yml b/roles/openstack_helm_infra_memcached/meta/main.yml
new file mode 100644
index 0000000..0157d71
--- /dev/null
+++ b/roles/openstack_helm_infra_memcached/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_infra_memcached_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_infra_memcached_chart_repo_url }}"
diff --git a/roles/openstack_helm_infra_memcached/tasks/main.yml b/roles/openstack_helm_infra_memcached/tasks/main.yml
new file mode 100644
index 0000000..491e3bc
--- /dev/null
+++ b/roles/openstack_helm_infra_memcached/tasks/main.yml
@@ -0,0 +1,122 @@
+# 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_infra_memcached_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_infra_memcached_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_infra_memcached_chart_name }}"
+
+- name: Generate Helm values comparison
+ ansible.builtin.include_role:
+ name: helm_diff
+ vars:
+ helm_diff_release_name: "{{ openstack_helm_infra_memcached_chart_name }}"
+ helm_diff_release_namespace: openstack
+ helm_diff_values: "{{ _openstack_helm_infra_memcached_values }}"
+ when:
+ - openstack_helm_infra_memcached_diff | bool
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_infra_memcached_chart_name }}"
+ chart_ref: "{{ openstack_helm_infra_memcached_chart_repo_name }}/{{ openstack_helm_infra_memcached_chart_name }}"
+ chart_version: 0.1.6
+ release_namespace: openstack
+ create_namespace: true
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_infra_memcached_values }}"
+
+- name: Create Service for metrics
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Service
+ metadata:
+ name: memcached-metrics
+ namespace: openstack
+ labels:
+ application: memcached
+ component: server
+ spec:
+ selector:
+ application: memcached
+ component: server
+ ports:
+ - name: metrics
+ port: 9150
+ targetPort: 9150
+
+- name: Create ServiceMonitor
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: monitoring.coreos.com/v1
+ kind: ServiceMonitor
+ metadata:
+ name: memcached
+ namespace: monitoring
+ labels:
+ release: kube-prometheus-stack
+ spec:
+ jobLabel: application
+ endpoints:
+ - port: "metrics"
+ path: "/metrics"
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ namespaceSelector:
+ matchNames:
+ - openstack
+ selector:
+ matchLabels:
+ application: memcached
+ component: server
+
+- name: Create PrometheusRule
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: monitoring.coreos.com/v1
+ kind: PrometheusRule
+ metadata:
+ name: memcached
+ namespace: monitoring
+ labels:
+ release: kube-prometheus-stack
+ spec:
+ groups:
+ - name: memcached
+ rules:
+ - alert: MemcachedDown
+ expr: memcached_up == 0
+ for: 5m
+ labels:
+ severity: critical
+ - alert: MemcachedConnectionLimitApproaching
+ expr: (memcached_current_connections / memcached_max_connections * 100) > 80
+ for: 5m
+ labels:
+ severity: warning
+ - alert: MemcachedConnectionLimitApproaching
+ expr: (memcached_current_connections / memcached_max_connections * 100) > 95
+ for: 5m
+ labels:
+ severity: critical
diff --git a/roles/openstack_helm_infra_memcached/vars/main.yml b/roles/openstack_helm_infra_memcached/vars/main.yml
new file mode 100644
index 0000000..4acb969
--- /dev/null
+++ b/roles/openstack_helm_infra_memcached/vars/main.yml
@@ -0,0 +1,24 @@
+# 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_infra_memcached_values: "{{ __openstack_helm_infra_memcached_values | combine(openstack_helm_infra_memcached_values, recursive=True) }}"
+__openstack_helm_infra_memcached_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ memcached: quay.io/vexxhost/memcached:1.6.9
+ prometheus_memcached_exporter: quay.io/vexxhost/memcached-exporter:v0.9.0-1
+ monitoring:
+ prometheus:
+ enabled: true
diff --git a/roles/openstack_helm_infra_openvswitch/defaults/main.yml b/roles/openstack_helm_infra_openvswitch/defaults/main.yml
new file mode 100644
index 0000000..c8c6a93
--- /dev/null
+++ b/roles/openstack_helm_infra_openvswitch/defaults/main.yml
@@ -0,0 +1,22 @@
+# 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_infra_openvswitch_chart_repo_name: openstack-helm-infra
+openstack_helm_infra_openvswitch_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm-infra/
+openstack_helm_infra_openvswitch_chart_name: openvswitch
+
+openstack_helm_infra_openvswitch_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_infra_openvswitch_image_tag: wallaby
+
+openstack_helm_infra_openvswitch_values: {}
diff --git a/roles/openstack_helm_infra_openvswitch/meta/main.yml b/roles/openstack_helm_infra_openvswitch/meta/main.yml
new file mode 100644
index 0000000..f31873c
--- /dev/null
+++ b/roles/openstack_helm_infra_openvswitch/meta/main.yml
@@ -0,0 +1,20 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_infra_openvswitch_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_infra_openvswitch_chart_repo_url }}"
+ - openstack_namespace
diff --git a/roles/openstack_helm_infra_openvswitch/tasks/main.yml b/roles/openstack_helm_infra_openvswitch/tasks/main.yml
new file mode 100644
index 0000000..372a5e4
--- /dev/null
+++ b/roles/openstack_helm_infra_openvswitch/tasks/main.yml
@@ -0,0 +1,30 @@
+# 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_infra_openvswitch_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_infra_openvswitch_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_infra_openvswitch_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_infra_openvswitch_chart_name }}"
+ chart_ref: "{{ openstack_helm_infra_openvswitch_chart_repo_name }}/{{ openstack_helm_infra_openvswitch_chart_name }}"
+ chart_version: 0.1.6
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_infra_openvswitch_values | combine(openstack_helm_infra_openvswitch_values, recursive=True) }}"
diff --git a/roles/openstack_helm_infra_openvswitch/vars/main.yml b/roles/openstack_helm_infra_openvswitch/vars/main.yml
new file mode 100644
index 0000000..e84639e
--- /dev/null
+++ b/roles/openstack_helm_infra_openvswitch/vars/main.yml
@@ -0,0 +1,21 @@
+# 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_infra_openvswitch_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ dep_check: "{{ openstack_helm_infra_openvswitch_image_repository }}/kubernetes-entrypoint:latest"
+ openvswitch_db_server: "{{ openstack_helm_infra_openvswitch_image_repository }}/openvswitch:{{ openstack_helm_infra_openvswitch_image_tag }}"
+ openvswitch_vswitchd: "{{ openstack_helm_infra_openvswitch_image_repository }}/openvswitch:{{ openstack_helm_infra_openvswitch_image_tag }}"
diff --git a/roles/openstack_helm_infra_rabbitmq/defaults/main.yml b/roles/openstack_helm_infra_rabbitmq/defaults/main.yml
new file mode 100644
index 0000000..b248ba7
--- /dev/null
+++ b/roles/openstack_helm_infra_rabbitmq/defaults/main.yml
@@ -0,0 +1,19 @@
+# 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_infra_rabbitmq_chart_repo_name: openstack-helm-infra
+openstack_helm_infra_rabbitmq_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm-infra/
+openstack_helm_infra_rabbitmq_chart_name: rabbitmq
+
+openstack_helm_infra_rabbitmq_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
diff --git a/roles/openstack_helm_infra_rabbitmq/meta/main.yml b/roles/openstack_helm_infra_rabbitmq/meta/main.yml
new file mode 100644
index 0000000..53614f8
--- /dev/null
+++ b/roles/openstack_helm_infra_rabbitmq/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_infra_rabbitmq_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_infra_rabbitmq_chart_repo_url }}"
diff --git a/roles/openstack_helm_infra_rabbitmq/tasks/main.yml b/roles/openstack_helm_infra_rabbitmq/tasks/main.yml
new file mode 100644
index 0000000..7e50b0e
--- /dev/null
+++ b/roles/openstack_helm_infra_rabbitmq/tasks/main.yml
@@ -0,0 +1,159 @@
+# 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_infra_rabbitmq_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_infra_rabbitmq_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_infra_rabbitmq_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_infra_rabbitmq_chart_name }}"
+ chart_ref: "{{ openstack_helm_infra_rabbitmq_chart_repo_name }}/{{ openstack_helm_infra_rabbitmq_chart_name }}"
+ chart_version: 0.1.15
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ dep_check: "{{ openstack_helm_infra_rabbitmq_image_repository }}/kubernetes-entrypoint:latest"
+ rabbitmq_init: "{{ openstack_helm_infra_rabbitmq_image_repository }}/cli:latest"
+ rabbitmq: "{{ openstack_helm_infra_rabbitmq_image_repository }}/rabbitmq:3.8.23"
+ pod:
+ replicas:
+ server: 3
+ conf:
+ enabled_plugins:
+ - rabbitmq_management
+ - rabbitmq_peer_discovery_k8s
+ - rabbitmq_prometheus
+ volume:
+ size: 10Gi
+ manifests:
+ ingress_management: false
+
+- name: Create Service for metrics
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Service
+ metadata:
+ name: rabbitmq-metrics
+ namespace: openstack
+ labels:
+ application: rabbitmq
+ component: server
+ spec:
+ selector:
+ application: rabbitmq
+ component: server
+ ports:
+ - name: metrics
+ port: 15692
+ targetPort: 15692
+
+- name: Create ServiceMonitor
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: monitoring.coreos.com/v1
+ kind: ServiceMonitor
+ metadata:
+ name: rabbitmq
+ namespace: monitoring
+ labels:
+ release: kube-prometheus-stack
+ spec:
+ jobLabel: application
+ endpoints:
+ - port: "metrics"
+ path: "/metrics"
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ namespaceSelector:
+ matchNames:
+ - openstack
+ selector:
+ matchLabels:
+ application: rabbitmq
+ component: server
+
+- name: Create PrometheusRule
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: monitoring.coreos.com/v1
+ kind: PrometheusRule
+ metadata:
+ name: rabbitmq
+ namespace: monitoring
+ labels:
+ release: kube-prometheus-stack
+ spec:
+ groups:
+ - name: rules
+ rules:
+ - alert: RabbitmqDown
+ expr: absent(rabbitmq_build_info)
+ for: 1m
+ labels:
+ severity: critical
+ - alert: RabbitmqNodeDown
+ expr: sum(rabbitmq_build_info) < 3
+ for: 1m
+ labels:
+ severity: critical
+ - alert: RabbitmqNodeNotDistributed
+ expr: erlang_vm_dist_node_state < 3
+ for: 1m
+ labels:
+ severity: critical
+ - alert: RabbitmqMemoryHigh
+ expr: rabbitmq_process_resident_memory_bytes / rabbitmq_resident_memory_limit_bytes > 0.80
+ labels:
+ severity: warning
+ - alert: RabbitmqMemoryHigh
+ expr: rabbitmq_process_resident_memory_bytes / rabbitmq_resident_memory_limit_bytes > 0.95
+ labels:
+ severity: critical
+ - alert: RabbitmqFileDescriptorsUsage
+ expr: rabbitmq_process_open_fds / rabbitmq_process_max_fds > 0.80
+ labels:
+ severity: warning
+ - alert: RabbitmqFileDescriptorsUsage
+ expr: rabbitmq_process_open_fds / rabbitmq_process_max_fds > 0.95
+ labels:
+ severity: critical
+ - alert: RabbitmqUnackedMessages
+ expr: sum(rabbitmq_queue_messages_unacked) BY (queue) > 1000
+ for: 5m
+ labels:
+ severity: warning
+ - alert: RabbitmqUnackedMessages
+ expr: sum(rabbitmq_queue_messages_unacked) BY (queue) > 1000
+ for: 1h
+ labels:
+ severity: critical
+ - alert: RabbitmqConnections
+ expr: rabbitmq_connections > 1000
+ labels:
+ severity: warning
diff --git a/roles/openstack_helm_ingress/defaults/main.yml b/roles/openstack_helm_ingress/defaults/main.yml
new file mode 100644
index 0000000..9ec5bd9
--- /dev/null
+++ b/roles/openstack_helm_ingress/defaults/main.yml
@@ -0,0 +1,16 @@
+# 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_ingress_annotations: {}
+openstack_helm_ingress_paths: []
diff --git a/roles/openstack_helm_ingress/tasks/main.yml b/roles/openstack_helm_ingress/tasks/main.yml
new file mode 100644
index 0000000..11b0cdf
--- /dev/null
+++ b/roles/openstack_helm_ingress/tasks/main.yml
@@ -0,0 +1,34 @@
+# 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: Create Ingress ({{ openstack_helm_ingress_endpoint }})
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Ingress
+ metadata:
+ name: "{{ openstack_helm_ingress_endpoint | replace('_', '-') }}"
+ namespace: openstack
+ annotations: "{{ _openstack_helm_ingress_annotations | combine(openstack_helm_ingress_annotations, recursive=True) }}"
+ spec:
+ ingressClassName: openstack
+ rules:
+ - host: "{{ openstack_helm_endpoints[openstack_helm_ingress_endpoint]['host_fqdn_override']['public']['host'] }}"
+ http:
+ paths: "{{ _openstack_helm_ingress_paths }}"
+ tls:
+ - secretName: "{{ openstack_helm_ingress_service_name }}-certs"
+ hosts:
+ - "{{ openstack_helm_endpoints[openstack_helm_ingress_endpoint]['host_fqdn_override']['public']['host'] }}"
diff --git a/roles/openstack_helm_ingress/vars/main.yml b/roles/openstack_helm_ingress/vars/main.yml
new file mode 100644
index 0000000..a000c50
--- /dev/null
+++ b/roles/openstack_helm_ingress/vars/main.yml
@@ -0,0 +1,26 @@
+# 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_ingress_annotations:
+ cert-manager.io/issuer: openstack
+
+_openstack_helm_ingress_paths: "{{ openstack_helm_ingress_paths + __openstack_helm_ingress_paths }}"
+__openstack_helm_ingress_paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: "{{ openstack_helm_ingress_service_name }}"
+ port:
+ number: "{{ openstack_helm_ingress_service_port }}"
diff --git a/roles/openstack_helm_keystone/defaults/main.yml b/roles/openstack_helm_keystone/defaults/main.yml
new file mode 100644
index 0000000..7f2358b
--- /dev/null
+++ b/roles/openstack_helm_keystone/defaults/main.yml
@@ -0,0 +1,23 @@
+# 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_keystone_chart_repo_name: openstack-helm
+openstack_helm_keystone_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_keystone_chart_name: keystone
+
+openstack_helm_keystone_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_keystone_image_tag: 19.0.1.dev11
+openstack_helm_keystone_heat_image_tag: wallaby
+
+openstack_helm_keystone_values: {}
diff --git a/roles/openstack_helm_keystone/meta/main.yml b/roles/openstack_helm_keystone/meta/main.yml
new file mode 100644
index 0000000..136ce7c
--- /dev/null
+++ b/roles/openstack_helm_keystone/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_keystone_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_keystone_chart_repo_url }}"
diff --git a/roles/openstack_helm_keystone/tasks/main.yml b/roles/openstack_helm_keystone/tasks/main.yml
new file mode 100644
index 0000000..45e2de5
--- /dev/null
+++ b/roles/openstack_helm_keystone/tasks/main.yml
@@ -0,0 +1,39 @@
+# 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_keystone_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_keystone_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_keystone_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_keystone_chart_name }}"
+ chart_ref: "{{ openstack_helm_keystone_chart_repo_name }}/{{ openstack_helm_keystone_chart_name }}"
+ chart_version: 0.2.19
+ release_namespace: openstack
+ create_namespace: true
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_keystone_values | combine(openstack_helm_keystone_values, recursive=True) }}"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: identity
+ openstack_helm_ingress_service_name: keystone-api
+ openstack_helm_ingress_service_port: 5000
diff --git a/roles/openstack_helm_keystone/vars/main.yml b/roles/openstack_helm_keystone/vars/main.yml
new file mode 100644
index 0000000..5b384c1
--- /dev/null
+++ b/roles/openstack_helm_keystone/vars/main.yml
@@ -0,0 +1,229 @@
+# 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_keystone_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_keystone_image_repository }}/heat:{{ openstack_helm_keystone_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_keystone_image_repository }}/heat:{{ openstack_helm_keystone_heat_image_tag }}"
+ db_init: "{{ openstack_helm_keystone_image_repository }}/heat:{{ openstack_helm_keystone_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_keystone_image_repository }}/kubernetes-entrypoint:latest"
+ keystone_api: "{{ openstack_helm_keystone_image_repository }}/keystone:{{ openstack_helm_keystone_image_tag }}"
+ keystone_credential_cleanup: "{{ openstack_helm_keystone_image_repository }}/heat:{{ openstack_helm_keystone_heat_image_tag }}"
+ keystone_credential_rotate: "{{ openstack_helm_keystone_image_repository }}/keystone:{{ openstack_helm_keystone_image_tag }}"
+ keystone_credential_setup: "{{ openstack_helm_keystone_image_repository }}/keystone:{{ openstack_helm_keystone_image_tag }}"
+ keystone_db_sync: "{{ openstack_helm_keystone_image_repository }}/keystone:{{ openstack_helm_keystone_image_tag }}"
+ keystone_domain_manage: "{{ openstack_helm_keystone_image_repository }}/keystone:{{ openstack_helm_keystone_image_tag }}"
+ keystone_fernet_rotate: "{{ openstack_helm_keystone_image_repository }}/keystone:{{ openstack_helm_keystone_image_tag }}"
+ keystone_fernet_setup: "{{ openstack_helm_keystone_image_repository }}/keystone:{{ openstack_helm_keystone_image_tag }}"
+ ks_user: "{{ openstack_helm_keystone_image_repository }}/heat:{{ openstack_helm_keystone_heat_image_tag }}"
+ rabbit_init: "{{ openstack_helm_keystone_image_repository }}/rabbitmq:3.8.23-management"
+ pod:
+ # mounts = {
+ # keystone_api = {
+ # keystone_api = {
+ # volumeMounts = [
+ # {
+ # name = kubernetes_config_map.keystone_ldap_ca.metadata[0].name
+ # mountPath = "/etc/keystone/ldap"
+ # },
+ # {
+ # name = kubernetes_config_map.keystone_openid_connect_metadata.metadata[0].name
+ # mountPath = "/var/lib/apache2/oidc"
+ # }
+ # ],
+ # volumes = [
+ # {
+ # name = kubernetes_config_map.keystone_ldap_ca.metadata[0].name
+ # configMap = {
+ # name = kubernetes_config_map.keystone_ldap_ca.metadata[0].name
+ # }
+ # },
+ # {
+ # name = kubernetes_config_map.keystone_openid_connect_metadata.metadata[0].name
+ # configMap = {
+ # name = kubernetes_config_map.keystone_openid_connect_metadata.metadata[0].name
+ # }
+ # }
+ # ]
+ # }
+ # }
+ # },
+ replicas:
+ api: 3
+ conf:
+ keystone:
+ DEFAULT:
+ log_config_append: null
+ auth:
+ methods: password,token,openid,application_credential
+ cors:
+ allowed_origins: "*"
+ federation:
+ assertion_prefix: OIDC-
+ remote_id_attribute: OIDC-iss
+ # TODO(mnaser): Lookup using openstack_helm_endpoints
+ trusted_dashboard: "https://{{ openstack_helm_endpoints_horizon_api_host }}/auth/websso/"
+ identity:
+ domain_configuration_from_database: true
+ manifests:
+ job_credential_cleanup: false
+ ingress_api: false
+ service_ingress_api: false
+# # LDAP configuration
+# yamlencode({
+# conf = {
+# ks_domains = {
+# for domain, details in var.keystone_ldap_domains : domain => {
+# identity = {
+# driver = "ldap"
+# }
+# ldap = merge({
+# tls_cacertfile = "/etc/keystone/ldap/${domain}.crt"
+# }, details.conf)
+# }
+# }
+# }
+# }),
+
+# # OpenID Connect
+# yamlencode({
+# bootstrap = {
+# script = <<-EOT
+# # Create role for publishing images
+# openstack role create --or-show image-publisher
+
+# # Add member role for admin user
+# openstack role add \
+# --user="$${OS_USERNAME}" \
+# --user-domain="$${OS_USER_DOMAIN_NAME}" \
+# --project-domain="$${OS_PROJECT_DOMAIN_NAME}" \
+# --project="$${OS_PROJECT_NAME}" \
+# "member"
+
+# # Create project for tempest-pushgateway
+# openstack project create --or-show \
+# "${kubernetes_secret.tempest_pushgateway.data.OS_PROJECT_NAME}"
+# openstack user create --or-show \
+# "${kubernetes_secret.tempest_pushgateway.data.OS_USERNAME}"
+# openstack user set \
+# --password="${kubernetes_secret.tempest_pushgateway.data.OS_PASSWORD}" \
+# "${kubernetes_secret.tempest_pushgateway.data.OS_USERNAME}"
+# openstack role add \
+# --user="${kubernetes_secret.tempest_pushgateway.data.OS_USERNAME}" \
+# --project="${kubernetes_secret.tempest_pushgateway.data.OS_PROJECT_NAME}" \
+# "member"
+
+# # Add admin user to default domain
+# openstack role add \
+# --user="$${OS_USERNAME}" \
+# --domain="$${OS_DEFAULT_DOMAIN}" \
+# "admin"
+# %{for name, config in var.keystone_openid_connect_idps}
+# # OpenID connect (${name})
+
+# # Create Identity provider if it doesn't exist
+# IDP_ID=$(openstack identity provider show ${name} -c id -f value || :)
+# if [ -z "$IDP_ID" ]; then
+# openstack identity provider create --remote-id ${config.issuer} ${name}
+# else
+# openstack identity provider set --remote-id ${config.issuer} ${name}
+# fi
+
+# # Generate mapping
+# cat <<EOF | tee /tmp/mapping.json
+# ${jsonencode(local.keystone_mappings[name])}
+# EOF
+
+# # Upload mapping to Keystone
+# MAPPING_ID=$(openstack mapping show ${name} -c id -f value || :)
+# if [ -z "$MAPPING_ID" ]; then
+# openstack mapping create --rules /tmp/mapping.json ${name}
+# else
+# openstack mapping set --rules /tmp/mapping.json ${name}
+# fi
+
+# # Create federation
+# FEDERATION_ID=$(openstack federation protocol show --identity-provider ${name} openid -c id -f value || :)
+# if [ -z "$FEDERATION_ID" ]; then
+# openstack federation protocol create --identity-provider ${name} --mapping ${name} openid
+# fi
+# %{endfor~}
+# EOT
+# }
+# conf = {
+# wsgi_keystone = <<-EOT
+# {{- $portInt := tuple "identity" "internal" "api" $ | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+
+# Listen 0.0.0.0:{{ $portInt }}
+
+# LogFormat "%h %l %u %t \"%r\" %>s %b \"%%{Referer}i\" \"%%{User-Agent}i\"" combined
+# LogFormat "%%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%%{Referer}i\" \"%%{User-Agent}i\"" proxy
+
+# SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
+# CustomLog /dev/stdout combined env=!forwarded
+# CustomLog /dev/stdout proxy env=forwarded
+
+# <VirtualHost *:{{ $portInt }}>
+# WSGIDaemonProcess keystone-public processes=4 threads=1 user=keystone group=keystone display-name=%%{GROUP}
+# WSGIProcessGroup keystone-public
+# WSGIScriptAlias / /var/www/cgi-bin/keystone/keystone-wsgi-public
+# WSGIApplicationGroup %%{GLOBAL}
+# WSGIPassAuthorization On
+# <IfVersion >= 2.4>
+# ErrorLogFormat "%%{cu}t %M"
+# </IfVersion>
+# ErrorLog /dev/stdout
+
+# SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
+# CustomLog /dev/stdout combined env=!forwarded
+# CustomLog /dev/stdout proxy env=forwarded
+
+# # OpenID connect
+# OIDCMetadataDir /var/lib/apache2/oidc
+# OIDCClaimPrefix "OIDC-"
+# OIDCSessionType client-cookie
+# OIDCCryptoPassphrase ${random_password.keystone_openid_connect_crypto_passphrase.result}
+# OIDCRedirectURLsAllowed ^https://${var.horizon_api_host}/auth/logout/$ ^https://${var.keystone_api_host}
+# OIDCOAuthVerifyJwksUri https://vexxhost.us.auth0.com/.well-known/jwks.json
+
+# OIDCRedirectURI https://${var.keystone_api_host}/v3/auth/OS-FEDERATION/identity_providers/redirect
+# <Location /v3/auth/OS-FEDERATION/identity_providers/redirect>
+# AuthType openid-connect
+# Require valid-user
+# </Location>
+# <Location /v3/auth/OS-FEDERATION/websso/openid>
+# AuthType openid-connect
+# Require valid-user
+# </Location>
+
+# %{for name, config in var.keystone_openid_connect_idps}
+# <Location /v3/auth/OS-FEDERATION/identity_providers/${name}/protocols/openid/websso>
+# OIDCDiscoverURL https://${var.keystone_api_host}/v3/auth/OS-FEDERATION/identity_providers/redirect?iss=${urlencode(config.issuer)}
+# AuthType openid-connect
+# Require valid-user
+# </Location>
+# <Location /v3/OS-FEDERATION/identity_providers/${name}/protocols/openid/auth>
+# LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
+# Header set Access-Control-Allow-Headers "Authorization,Content-Type"
+# Header set Access-Control-Allow-Origin "*"
+# AuthType oauth20
+# Require valid-user
+# </Location>
+# %{endfor}
+# </VirtualHost>
+# EOT
+# }
+# }),
diff --git a/roles/openstack_helm_migrate_to_percona_xtradb_cluster/tasks/main.yml b/roles/openstack_helm_migrate_to_percona_xtradb_cluster/tasks/main.yml
new file mode 100644
index 0000000..5091f6f
--- /dev/null
+++ b/roles/openstack_helm_migrate_to_percona_xtradb_cluster/tasks/main.yml
@@ -0,0 +1,101 @@
+# 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: Get the IP address for the legacy MariaDB service
+ kubernetes.core.k8s_info:
+ api_version: v1
+ kind: Service
+ name: mariadb
+ namespace: openstack
+ register: _openstack_helm_migrate_to_percona_xtradb_cluster_legacy_service
+ when: _openstack_helm_migrate_to_percona_xtradb_cluster_legacy_ip is undefined
+
+- name: Get the IP address for the new Percona XtraDB service
+ kubernetes.core.k8s_info:
+ api_version: v1
+ kind: Service
+ name: percona-xtradb-haproxy
+ namespace: openstack
+ register: _openstack_helm_migrate_to_percona_xtradb_cluster_service
+ when: _openstack_helm_migrate_to_percona_xtradb_cluster_ip is undefined
+
+- name: Get current values for Helm chart & fail if it already points to Percona XtraDB Cluster
+ kubernetes.core.helm_info:
+ name: "{{ openstack_helm_migrate_to_percona_xtradb_cluster_release_name }}"
+ release_namespace: "{{ openstack_helm_migrate_to_percona_xtradb_cluster_release_namespace }}"
+ register: _openstack_helm_migrate_to_percona_xtradb_cluster_helm_info
+ failed_when: _openstack_helm_migrate_to_percona_xtradb_cluster_helm_info.status['values']['endpoints']['oslo_db'].get('hosts', {}).get('default', '') == 'percona-xtradb-haproxy'
+
+- name: Set facts for database endpoints
+ ansible.builtin.set_fact:
+ _openstack_helm_migrate_to_percona_xtradb_cluster_legacy_ip: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_legacy_service.resources[0]['spec']['clusterIP'] }}"
+ _openstack_helm_migrate_to_percona_xtradb_cluster_legacy_password: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_helm_info.status['values']['endpoints']['oslo_db']['auth']['admin']['password'] }}"
+ _openstack_helm_migrate_to_percona_xtradb_cluster_ip: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_service.resources[0]['spec']['clusterIP'] }}"
+ _openstack_helm_migrate_to_percona_xtradb_cluster_password: "{{ openstack_helm_endpoints['oslo_db']['auth']['admin']['password'] }}"
+
+- name: Ensure PyMySQL packages are installed
+ ansible.builtin.pip:
+ name: PyMySQL
+
+- name: Check if database already exists & fail if it already exists
+ community.mysql.mysql_db:
+ login_host: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_ip }}"
+ login_user: root
+ login_password: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_password }}"
+ name: "{{ item }}"
+ state: present
+ check_mode: true
+ register: _openstack_helm_migrate_to_percona_xtradb_cluster_db_check
+ failed_when: _openstack_helm_migrate_to_percona_xtradb_cluster_db_check is not changed
+ loop: "{{ openstack_helm_migrate_to_percona_xtradb_cluster_databases }}"
+
+- name: Scale down replicas to 0 for database facing services
+ kubernetes.core.k8s_scale:
+ api_version: v1
+ kind: "{{ item.kind }}"
+ name: "{{ item.name }}"
+ namespace: "{{ openstack_helm_migrate_to_percona_xtradb_cluster_release_namespace }}"
+ replicas: 0
+ loop: "{{ openstack_helm_migrate_to_percona_xtradb_cluster_services }}"
+
+- name: Create temporary file for database dump
+ ansible.builtin.tempfile:
+ state: file
+ prefix: "{{ openstack_helm_migrate_to_percona_xtradb_cluster_release_name }}"
+ suffix: .sql
+ register: _openstack_helm_migrate_to_percona_xtradb_cluster_file
+
+- name: Dump all of the databases to the local system
+ community.mysql.mysql_db:
+ login_host: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_legacy_ip }}"
+ login_user: root
+ login_password: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_legacy_password }}"
+ name: "{{ openstack_helm_migrate_to_percona_xtradb_cluster_databases }}"
+ state: dump
+ target: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_file.path }}"
+ skip_lock_tables: true
+ dump_extra_args: --skip-add-locks
+ async: 7200
+ poll: 5
+
+- name: Import databases to the new Percona XtraDB Cluster
+ community.mysql.mysql_db:
+ login_host: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_ip }}"
+ login_user: root
+ login_password: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_password }}"
+ name: "{{ (openstack_helm_migrate_to_percona_xtradb_cluster_databases | length > 1) | ternary('all', openstack_helm_migrate_to_percona_xtradb_cluster_databases) }}"
+ state: import
+ target: "{{ _openstack_helm_migrate_to_percona_xtradb_cluster_file.path }}"
+ async: 7200
+ poll: 5
diff --git a/roles/openstack_helm_neutron/defaults/main.yml b/roles/openstack_helm_neutron/defaults/main.yml
new file mode 100644
index 0000000..e81f9f8
--- /dev/null
+++ b/roles/openstack_helm_neutron/defaults/main.yml
@@ -0,0 +1,25 @@
+# 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_neutron_chart_repo_name: openstack-helm
+openstack_helm_neutron_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_neutron_chart_name: neutron
+
+openstack_helm_neutron_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_neutron_image_tag: 18.2.1.dev7-6
+openstack_helm_neutron_heat_image_tag: wallaby
+
+openstack_helm_neutron_values: {}
+
+openstack_helm_neutron_networks: []
diff --git a/roles/openstack_helm_neutron/meta/main.yml b/roles/openstack_helm_neutron/meta/main.yml
new file mode 100644
index 0000000..6c6c7e1
--- /dev/null
+++ b/roles/openstack_helm_neutron/meta/main.yml
@@ -0,0 +1,26 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_neutron_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_neutron_chart_repo_url }}"
+ - cilium
+ - openstack_namespace
+ - percona_xtradb_cluster
+ - openstack_helm_infra_memcached
+ - openstack_helm_infra_rabbitmq
+ - openstack_helm_infra_openvswitch
+ - openstack_helm_keystone
diff --git a/roles/openstack_helm_neutron/tasks/main.yml b/roles/openstack_helm_neutron/tasks/main.yml
new file mode 100644
index 0000000..bca4586
--- /dev/null
+++ b/roles/openstack_helm_neutron/tasks/main.yml
@@ -0,0 +1,87 @@
+# 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_neutron_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_neutron_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_neutron_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_neutron_chart_name }}"
+ chart_ref: "{{ openstack_helm_neutron_chart_repo_name }}/{{ openstack_helm_neutron_chart_name }}"
+ chart_version: 0.2.11
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_neutron_values | combine(openstack_helm_neutron_values, recursive=True) }}"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: network
+ openstack_helm_ingress_service_name: neutron-server
+ openstack_helm_ingress_service_port: 9696
+
+- name: Create networks
+ openstack.cloud.network:
+ auth:
+ auth_url: "https://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}"
+ username: "{{ openstack_helm_endpoints['identity']['auth']['admin']['username'] }}"
+ password: "{{ openstack_helm_endpoints['identity']['auth']['admin']['password'] }}"
+ project_name: admin
+ user_domain_name: Default
+ project_domain_name: Default
+ region_name: "{{ openstack_helm_endpoints['identity']['auth']['neutron']['region_name'] }}"
+ # Network settings
+ name: "{{ item.name }}"
+ external: "{{ item.external | default(omit) }}"
+ shared: "{{ item.shared | default(omit) }}"
+ mtu_size: "{{ item.mtu_size | default(omit) }}"
+ port_security_enabled: "{{ item.port_security_enabled | default(omit) }}"
+ provider_network_type: "{{ item.provider_network_type | default(omit) }}"
+ provider_physical_network: "{{ item.provider_physical_network | default(omit) }}"
+ provider_segmentation_id: "{{ item.provider_segmentation_id | default(omit) }}"
+ loop: "{{ openstack_helm_neutron_networks }}"
+
+- name: Create subnets
+ openstack.cloud.subnet:
+ auth:
+ auth_url: "https://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}"
+ username: "{{ openstack_helm_endpoints['identity']['auth']['admin']['username'] }}"
+ password: "{{ openstack_helm_endpoints['identity']['auth']['admin']['password'] }}"
+ project_name: admin
+ user_domain_name: Default
+ project_domain_name: Default
+ region_name: "{{ openstack_helm_endpoints['identity']['auth']['neutron']['region_name'] }}"
+ # Subnet settings
+ network_name: "{{ item.0.name }}"
+ name: "{{ item.1.name }}"
+ ip_version: "{{ item.1.ip_version | default(omit) }}"
+ cidr: "{{ item.1.cidr | default(omit) }}"
+ gateway_ip: "{{ item.1.gateway_ip | default(omit) }}"
+ no_gateway_ip: "{{ item.1.no_gateway_ip | default(omit) }}"
+ allocation_pool_start: "{{ item.1.allocation_pool_start | default(omit) }}"
+ allocation_pool_end: "{{ item.1.allocation_pool_end | default(omit) }}"
+ dns_nameservers: "{{ item.1.dns_nameservers | default(omit) }}"
+ enable_dhcp: "{{ item.1.enable_dhcp | default(omit) }}"
+ host_routes: "{{ item.1.host_routes | default(omit) }}"
+ ipv6_address_mode: "{{ item.1.ipv6_address_mode | default(omit) }}"
+ ipv6_ra_mode: "{{ item.1.ipv6_ra_mode | default(omit) }}"
+ with_subelements:
+ - "{{ openstack_helm_neutron_networks }}"
+ - subnets
diff --git a/roles/openstack_helm_neutron/vars/main.yml b/roles/openstack_helm_neutron/vars/main.yml
new file mode 100644
index 0000000..d30456c
--- /dev/null
+++ b/roles/openstack_helm_neutron/vars/main.yml
@@ -0,0 +1,82 @@
+# 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_neutron_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_neutron_image_repository }}/heat:{{ openstack_helm_neutron_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_neutron_image_repository }}/heat:{{ openstack_helm_neutron_heat_image_tag }}"
+ db_init: "{{ openstack_helm_neutron_image_repository }}/heat:{{ openstack_helm_neutron_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_neutron_image_repository }}/kubernetes-entrypoint:latest"
+ ks_endpoints: "{{ openstack_helm_neutron_image_repository }}/heat:{{ openstack_helm_neutron_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_neutron_image_repository }}/heat:{{ openstack_helm_neutron_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_neutron_image_repository }}/heat:{{ openstack_helm_neutron_heat_image_tag }}"
+ neutron_bagpipe_bgp: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_db_sync: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_dhcp: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_ironic_agent: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_l2gw: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_l3: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_linuxbridge_agent: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_metadata: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_netns_cleanup_cron: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_openvswitch_agent: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_server: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_sriov_agent_init: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ neutron_sriov_agent: "{{ openstack_helm_neutron_image_repository }}/neutron:{{ openstack_helm_neutron_image_tag }}"
+ rabbit_init: "{{ openstack_helm_neutron_image_repository }}/rabbitmq:3.8.23-management"
+ pod:
+ replicas:
+ server: 3
+ conf:
+ paste:
+ composite:neutronapi_v2_0:
+ keystone: cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
+ neutron:
+ DEFAULT:
+ api_workers: 8
+ dhcp_agents_per_network: 3
+ log_config_append: null
+ rpc_workers: 8
+ service_plugins: router,vpnaas
+ cors:
+ allowed_origin: "*"
+ service_providers:
+ service_provider: VPN:strongswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
+ dhcp_agent:
+ DEFAULT:
+ dnsmasq_dns_servers: 1.1.1.1
+ enable_isolated_metadata: true
+ l3_agent:
+ AGENT:
+ extensions: vpnaas
+ vpnagent:
+ vpn_device_driver: neutron_vpnaas.services.vpn.device_drivers.strongswan_ipsec.StrongSwanDriver
+ metadata_agent:
+ DEFAULT:
+ nova_metadata_port: 8776
+ metadata_proxy_shared_secret: "{{ openstack_helm_endpoints['compute_metadata']['secret'] }}"
+ plugins:
+ ml2_conf:
+ ml2:
+ extension_drivers: port_security,dns
+ type_drivers: flat,gre,vlan,vxlan
+ ml2_type_gre:
+ tunnel_id_ranges: 1:1000
+ ml2_type_vlan:
+ network_vlan_ranges: external:1:4094
+ manifests:
+ ingress_server: false
+ service_ingress_server: false
diff --git a/roles/openstack_helm_nova/defaults/main.yml b/roles/openstack_helm_nova/defaults/main.yml
new file mode 100644
index 0000000..75ad162
--- /dev/null
+++ b/roles/openstack_helm_nova/defaults/main.yml
@@ -0,0 +1,29 @@
+# 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_nova_chart_repo_name: openstack-helm
+openstack_helm_nova_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_nova_chart_name: nova
+
+openstack_helm_nova_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_nova_image_tag: 23.1.1.dev11
+openstack_helm_nova_ssh_image_tag: wallaby
+openstack_helm_nova_heat_image_tag: wallaby
+
+openstack_helm_nova_diff: false
+openstack_helm_nova_migrate_from_mariadb: false
+
+openstack_helm_nova_values: {}
+
+openstack_helm_nova_flavors: []
diff --git a/roles/openstack_helm_nova/meta/main.yml b/roles/openstack_helm_nova/meta/main.yml
new file mode 100644
index 0000000..6a725f3
--- /dev/null
+++ b/roles/openstack_helm_nova/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_nova_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_nova_chart_repo_url }}"
diff --git a/roles/openstack_helm_nova/tasks/main.yml b/roles/openstack_helm_nova/tasks/main.yml
new file mode 100644
index 0000000..db1f2eb
--- /dev/null
+++ b/roles/openstack_helm_nova/tasks/main.yml
@@ -0,0 +1,104 @@
+# 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_nova_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_nova_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_nova_chart_name }}"
+
+- name: Generate Helm values comparison
+ ansible.builtin.include_role:
+ name: helm_diff
+ vars:
+ helm_diff_release_name: "{{ openstack_helm_nova_chart_name }}"
+ helm_diff_release_namespace: openstack
+ helm_diff_values: "{{ _openstack_helm_nova_values }}"
+ when:
+ - openstack_helm_nova_diff | bool
+
+- name: Migrate database from MariaDB to Percona XtraDB Cluster
+ ansible.builtin.include_role:
+ name: openstack_helm_migrate_to_percona_xtradb_cluster
+ vars:
+ openstack_helm_migrate_to_percona_xtradb_cluster_release_name: "{{ openstack_helm_nova_chart_name }}"
+ openstack_helm_migrate_to_percona_xtradb_cluster_release_namespace: openstack
+ openstack_helm_migrate_to_percona_xtradb_cluster_databases:
+ - nova
+ - nova_api
+ - nova_cell0
+ openstack_helm_migrate_to_percona_xtradb_cluster_services:
+ - kind: Deployment
+ name: nova-api-metadata
+ - kind: Deployment
+ name: nova-api-osapi
+ - kind: Deployment
+ name: nova-conductor
+ - kind: Deployment
+ name: nova-scheduler
+ when:
+ - openstack_helm_nova_migrate_from_mariadb | bool
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_nova_chart_name }}"
+ chart_ref: "{{ openstack_helm_nova_chart_repo_name }}/{{ openstack_helm_nova_chart_name }}"
+ chart_version: 0.2.30
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_nova_values }}"
+ # NOTE(mnaser): This is a a workaround due to the fact that Nova's online
+ # data migrations take forever.
+ wait_timeout: 10m
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: compute
+ openstack_helm_ingress_service_name: nova-api
+ openstack_helm_ingress_service_port: 8774
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: compute_novnc_proxy
+ openstack_helm_ingress_service_name: nova-novncproxy
+ openstack_helm_ingress_service_port: 6080
+
+- name: Create flavors
+ openstack.cloud.compute_flavor:
+ auth:
+ auth_url: "https://{{ openstack_helm_endpoints['identity']['host_fqdn_override']['public']['host'] }}"
+ username: "{{ openstack_helm_endpoints['identity']['auth']['admin']['username'] }}"
+ password: "{{ openstack_helm_endpoints['identity']['auth']['admin']['password'] }}"
+ project_name: admin
+ user_domain_name: Default
+ project_domain_name: Default
+ region_name: "{{ openstack_helm_endpoints['identity']['auth']['neutron']['region_name'] }}"
+ # Flavor settings
+ flavorid: "{{ item.flavorid | default(omit) }}"
+ name: "{{ item.name }}"
+ vcpus: "{{ item.vcpus }}"
+ ram: "{{ item.ram }}"
+ disk: "{{ item.disk | default(omit) }}"
+ ephemeral: "{{ item.ephemeral | default(omit) }}"
+ swap: "{{ item.swap | default(omit) }}"
+ is_public: "{{ item.is_public | default(omit) }}"
+ rxtx_factor: "{{ item.rxtx_factor | default(omit) }}"
+ extra_specs: "{{ item.extra_specs | default(omit) }}"
+ loop: "{{ openstack_helm_nova_flavors }}"
diff --git a/roles/openstack_helm_nova/vars/main.yml b/roles/openstack_helm_nova/vars/main.yml
new file mode 100644
index 0000000..bc22c7c
--- /dev/null
+++ b/roles/openstack_helm_nova/vars/main.yml
@@ -0,0 +1,117 @@
+# 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_nova_values: "{{ __openstack_helm_nova_values | combine(openstack_helm_nova_values, recursive=True) }}"
+__openstack_helm_nova_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ labels:
+ agent:
+ compute_ironic:
+ node_selector_key: openstack-control-plane
+ node_selector_value: enabled
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_nova_image_repository }}/heat:{{ openstack_helm_nova_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_nova_image_repository }}/heat:{{ openstack_helm_nova_heat_image_tag }}"
+ db_init: "{{ openstack_helm_nova_image_repository }}/heat:{{ openstack_helm_nova_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_nova_image_repository }}/kubernetes-entrypoint:latest"
+ ks_endpoints: "{{ openstack_helm_nova_image_repository }}/heat:{{ openstack_helm_nova_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_nova_image_repository }}/heat:{{ openstack_helm_nova_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_nova_image_repository }}/heat:{{ openstack_helm_nova_heat_image_tag }}"
+ nova_api: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_archive_deleted_rows: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_cell_setup_init: "{{ openstack_helm_nova_image_repository }}/heat:{{ openstack_helm_nova_heat_image_tag }}"
+ nova_cell_setup: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ # TODO(mnaser): Fix Ironic images
+ nova_compute_ironic: "docker.io/kolla/ubuntu-source-nova-compute-ironic:wallaby"
+ nova_compute_ssh: "{{ openstack_helm_nova_image_repository }}/nova-ssh:{{ openstack_helm_nova_ssh_image_tag }}"
+ nova_compute: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_conductor: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_consoleauth: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_db_sync: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_novncproxy_assets: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_novncproxy: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_placement: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_scheduler: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_service_cleaner: "{{ openstack_helm_nova_image_repository }}/cli:latest"
+ nova_spiceproxy_assets: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ nova_spiceproxy: "{{ openstack_helm_nova_image_repository }}/nova:{{ openstack_helm_nova_image_tag }}"
+ rabbit_init: "{{ openstack_helm_nova_image_repository }}/rabbitmq:3.8.23-management"
+ bootstrap:
+ structured:
+ flavors:
+ enabled: false
+ pod:
+ replicas:
+ api_metadata: 3
+ osapi: 3
+ conductor: 3
+ scheduler: 3
+ novncproxy: 3
+ spiceproxy: 3
+ conf:
+ paste:
+ composite:openstack_compute_api_v21:
+ keystone: cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21
+ composite:openstack_compute_api_v21_legacy_v2_compatible:
+ keystone: cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken keystonecontext legacy_v2_compatible osapi_compute_app_v21
+ nova:
+ DEFAULT:
+ cpu_allocation_ratio: 4.5
+ ram_allocation_ratio: 0.9
+ disk_allocation_ratio: 3.0
+ resume_guests_state_on_host_boot: true
+ osapi_compute_workers: 8
+ metadata_workers: 8
+ cache:
+ backend: oslo_cache.memcache_pool
+ cinder:
+ catalog_info: volumev3::internalURL
+ conductor:
+ workers: 8
+ cors:
+ allowed_origin: "*"
+ allow_headers: "X-Auth-Token,X-OpenStack-Nova-API-Version"
+ filter_scheduler:
+ enabled_filters: ComputeFilter, AggregateTypeAffinityFilter, ComputeCapabilitiesFilter, PciPassthroughFilter, ImagePropertiesFilter, ServerGroupAntiAffinityFilter, ServerGroupAffinityFilter
+ image_properties_default_architecture: x86_64
+ max_instances_per_host: 200
+ glance:
+ enable_rbd_download: true
+ neutron:
+ metadata_proxy_shared_secret: "{{ openstack_helm_endpoints['compute_metadata']['secret'] }}"
+ scheduler:
+ workers: 8
+ nova_ironic:
+ DEFAULT:
+ log_config_append: null
+ force_config_drive: true
+ manifests:
+ deployment_consoleauth: false
+ deployment_placement: false
+ ingress_metadata: false
+ ingress_novncproxy: false
+ ingress_osapi: false
+ ingress_placement: false
+ job_db_init_placement: false
+ job_ks_placement_endpoints: false
+ job_ks_placement_service: false
+ job_ks_placement_user: false
+ secret_keystone_placement: false
+ service_ingress_metadata: false
+ service_ingress_novncproxy: false
+ service_ingress_osapi: false
+ service_ingress_placement: false
+ service_placement: false
+ statefulset_compute_ironic: true
diff --git a/roles/openstack_helm_placement/defaults/main.yml b/roles/openstack_helm_placement/defaults/main.yml
new file mode 100644
index 0000000..113b39b
--- /dev/null
+++ b/roles/openstack_helm_placement/defaults/main.yml
@@ -0,0 +1,23 @@
+# 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_placement_chart_repo_name: openstack-helm
+openstack_helm_placement_chart_repo_url: https://tarballs.opendev.org/openstack/openstack-helm/
+openstack_helm_placement_chart_name: placement
+
+openstack_helm_placement_image_repository: "{{ atmosphere_image_repository | default('us-docker.pkg.dev/vexxhost-infra/openstack') }}"
+openstack_helm_placement_image_tag: 5.0.1
+openstack_helm_placement_heat_image_tag: wallaby
+
+openstack_helm_placement_values: {}
diff --git a/roles/openstack_helm_placement/meta/main.yml b/roles/openstack_helm_placement/meta/main.yml
new file mode 100644
index 0000000..c0fb81a
--- /dev/null
+++ b/roles/openstack_helm_placement/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: "{{ openstack_helm_placement_chart_repo_name }}"
+ helm_repository_repo_url: "{{ openstack_helm_placement_chart_repo_url }}"
diff --git a/roles/openstack_helm_placement/tasks/main.yml b/roles/openstack_helm_placement/tasks/main.yml
new file mode 100644
index 0000000..6c39459
--- /dev/null
+++ b/roles/openstack_helm_placement/tasks/main.yml
@@ -0,0 +1,38 @@
+# 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_placement_chart_repo_name }}"
+ openstack_helm_endpoints_repo_url: "{{ openstack_helm_placement_chart_repo_url }}"
+ openstack_helm_endpoints_chart: "{{ openstack_helm_placement_chart_name }}"
+
+- name: Deploy Helm chart
+ kubernetes.core.helm:
+ name: "{{ openstack_helm_placement_chart_name }}"
+ chart_ref: "{{ openstack_helm_placement_chart_repo_name }}/{{ openstack_helm_placement_chart_name }}"
+ chart_version: 0.2.5
+ release_namespace: openstack
+ kubeconfig: /etc/kubernetes/admin.conf
+ values: "{{ _openstack_helm_placement_values | combine(openstack_helm_placement_values, recursive=True) }}"
+
+- name: Create Ingress
+ ansible.builtin.include_role:
+ name: openstack_helm_ingress
+ vars:
+ openstack_helm_ingress_endpoint: placement
+ openstack_helm_ingress_service_name: placement-api
+ openstack_helm_ingress_service_port: 8778
diff --git a/roles/openstack_helm_placement/vars/main.yml b/roles/openstack_helm_placement/vars/main.yml
new file mode 100644
index 0000000..cd47f82
--- /dev/null
+++ b/roles/openstack_helm_placement/vars/main.yml
@@ -0,0 +1,38 @@
+# 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_placement_values:
+ endpoints: "{{ openstack_helm_endpoints }}"
+ images:
+ tags:
+ bootstrap: "{{ openstack_helm_placement_image_repository }}/heat:{{ openstack_helm_placement_heat_image_tag }}"
+ db_drop: "{{ openstack_helm_placement_image_repository }}/heat:{{ openstack_helm_placement_heat_image_tag }}"
+ db_init: "{{ openstack_helm_placement_image_repository }}/heat:{{ openstack_helm_placement_heat_image_tag }}"
+ dep_check: "{{ openstack_helm_placement_image_repository }}/kubernetes-entrypoint:latest"
+ ks_endpoints: "{{ openstack_helm_placement_image_repository }}/heat:{{ openstack_helm_placement_heat_image_tag }}"
+ ks_service: "{{ openstack_helm_placement_image_repository }}/heat:{{ openstack_helm_placement_heat_image_tag }}"
+ ks_user: "{{ openstack_helm_placement_image_repository }}/heat:{{ openstack_helm_placement_heat_image_tag }}"
+ placement_db_sync: "{{ openstack_helm_placement_image_repository }}/placement:{{ openstack_helm_placement_image_tag }}"
+ placement: "{{ openstack_helm_placement_image_repository }}/placement:{{ openstack_helm_placement_image_tag }}"
+ rabbit_init: "{{ openstack_helm_placement_image_repository }}/rabbitmq:3.8.23-management"
+ pod:
+ replicas:
+ api: 3
+ conf:
+ placement:
+ DEFAULT:
+ log_config_append: null
+ manifests:
+ ingress: false
+ service_ingress: false
diff --git a/roles/openstack_namespace/tasks/main.yml b/roles/openstack_namespace/tasks/main.yml
new file mode 100644
index 0000000..a864a09
--- /dev/null
+++ b/roles/openstack_namespace/tasks/main.yml
@@ -0,0 +1,22 @@
+# 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: Create namespace
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: v1
+ kind: Namespace
+ metadata:
+ name: openstack
diff --git a/roles/percona_xtradb_cluster/meta/main.yml b/roles/percona_xtradb_cluster/meta/main.yml
new file mode 100644
index 0000000..6b1f74e
--- /dev/null
+++ b/roles/percona_xtradb_cluster/meta/main.yml
@@ -0,0 +1,19 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: percona
+ helm_repository_repo_url: https://percona.github.io/percona-helm-charts/
diff --git a/roles/percona_xtradb_cluster/tasks/main.yml b/roles/percona_xtradb_cluster/tasks/main.yml
new file mode 100644
index 0000000..81c35cd
--- /dev/null
+++ b/roles/percona_xtradb_cluster/tasks/main.yml
@@ -0,0 +1,180 @@
+# 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: Deploy Helm chart
+ kubernetes.core.helm:
+ name: pxc-operator
+ chart_ref: percona/pxc-operator
+ chart_version: 1.10.0
+ release_namespace: openstack
+ create_namespace: true
+ kubeconfig: /etc/kubernetes/admin.conf
+
+- name: Deploy cluster
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: pxc.percona.com/v1-10-0
+ kind: PerconaXtraDBCluster
+ metadata:
+ name: percona-xtradb
+ namespace: openstack
+ spec:
+ crVersion: 1.10.0
+ secretsName: percona-xtradb
+ pxc:
+ size: 3
+ image: percona/percona-xtradb-cluster:5.7.36-31.55
+ autoRecovery: true
+ configuration: |
+ [mysqld]
+ max_connections=8192
+ sidecars:
+ - name: exporter
+ image: quay.io/prometheus/mysqld-exporter:v0.14.0
+ ports:
+ - name: metrics
+ containerPort: 9104
+ livenessProbe:
+ httpGet:
+ path: /
+ port: 9104
+ env:
+ - name: MONITOR_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: percona-xtradb
+ key: monitor
+ - name: DATA_SOURCE_NAME
+ value: "monitor:$(MONITOR_PASSWORD)@(localhost:3306)/"
+ nodeSelector:
+ openstack-control-plane: enabled
+ volumeSpec:
+ persistentVolumeClaim:
+ resources:
+ requests:
+ storage: 160Gi
+ haproxy:
+ enabled: true
+ size: 3
+ image: percona/percona-xtradb-cluster-operator:1.10.0-haproxy
+ nodeSelector:
+ openstack-control-plane: enabled
+ wait: true
+ wait_timeout: 600
+ wait_condition:
+ type: "ready"
+ status: "True"
+
+- name: Create PodMonitor
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: monitoring.coreos.com/v1
+ kind: PodMonitor
+ metadata:
+ name: percona-xtradb-pxc
+ namespace: monitoring
+ labels:
+ release: kube-prometheus-stack
+ spec:
+ jobLabel: app.kubernetes.io/component
+ podMetricsEndpoints:
+ - port: metrics
+ path: /metrics
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - action: "labeldrop"
+ regex: "^(container|endpoint|namespace|pod|service)$"
+ namespaceSelector:
+ matchNames:
+ - openstack
+ selector:
+ matchLabels:
+ app.kubernetes.io/component: pxc
+ app.kubernetes.io/instance: percona-xtradb
+
+- name: Create PrometheusRule
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: monitoring.coreos.com/v1
+ kind: PrometheusRule
+ metadata:
+ name: percona-xtradb-pxc
+ namespace: monitoring
+ labels:
+ release: kube-prometheus-stack
+ spec:
+ groups:
+ # TODO: basic rules
+ - name: general
+ rules:
+ - alert: MySQLDown
+ expr: mysql_up != 1
+ for: 5m
+ labels:
+ severity: critical
+ - alert: MysqlTooManyConnections
+ expr: max_over_time(mysql_global_status_threads_connected[1m]) / mysql_global_variables_max_connections * 100 > 80
+ for: 2m
+ labels:
+ severity: warning
+ - alert: MysqlHighThreadsRunning
+ expr: max_over_time(mysql_global_status_threads_running[1m]) / mysql_global_variables_max_connections * 100 > 60
+ for: 2m
+ labels:
+ severity: warning
+ - alert: MysqlSlowQueries
+ expr: increase(mysql_global_status_slow_queries[1m]) > 0
+ for: 2m
+ labels:
+ severity: warning
+ - name: galera
+ rules:
+ - alert: MySQLGaleraNotReady
+ expr: mysql_global_status_wsrep_ready != 1
+ for: 5m
+ labels:
+ severity: critical
+ - alert: MySQLGaleraOutOfSync
+ expr: mysql_global_status_wsrep_local_state != 4 and mysql_global_variables_wsrep_desync == 0
+ for: 5m
+ labels:
+ severity: critical
+ - alert: MySQLGaleraDonorFallingBehind
+ expr: mysql_global_status_wsrep_local_state == 2 and mysql_global_status_wsrep_local_recv_queue > 100
+ for: 5m
+ labels:
+ severity: warning
+ - alert: MySQLReplicationNotRunning
+ expr: mysql_slave_status_slave_io_running == 0 or mysql_slave_status_slave_sql_running == 0
+ for: 2m
+ labels:
+ severity: critical
+ - alert: MySQLReplicationLag
+ expr: (instance:mysql_slave_lag_seconds > 30) and on(instance) (predict_linear(instance:mysql_slave_lag_seconds[5m], 60 * 2) > 0)
+ for: 1m
+ labels:
+ severity: critical
+ - alert: MySQLHeartbeatLag
+ expr: (instance:mysql_heartbeat_lag_seconds > 30) and on(instance) (predict_linear(instance:mysql_heartbeat_lag_seconds[5m], 60 * 2) > 0)
+ for: 1m
+ labels:
+ severity: critical
+ - alert: MySQLInnoDBLogWaits
+ expr: rate(mysql_global_status_innodb_log_waits[15m]) > 10
+ labels:
+ severity: warning
diff --git a/roles/prometheus_pushgateway/meta/main.yml b/roles/prometheus_pushgateway/meta/main.yml
new file mode 100644
index 0000000..8da9c00
--- /dev/null
+++ b/roles/prometheus_pushgateway/meta/main.yml
@@ -0,0 +1,21 @@
+# 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.
+
+dependencies:
+ - role: helm_repository
+ vars:
+ helm_repository_name: prometheus-community
+ helm_repository_repo_url: https://prometheus-community.github.io/helm-charts
+ - cilium
+ - kube_prometheus_stack
diff --git a/roles/prometheus_pushgateway/tasks/main.yml b/roles/prometheus_pushgateway/tasks/main.yml
new file mode 100644
index 0000000..5042914
--- /dev/null
+++ b/roles/prometheus_pushgateway/tasks/main.yml
@@ -0,0 +1,34 @@
+# 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: Deploy Helm chart
+ kubernetes.core.helm:
+ name: prometheus-pushgateway
+ chart_ref: prometheus-community/prometheus-pushgateway
+ chart_version: 1.16.0
+ release_namespace: monitoring
+ kubeconfig: /etc/kubernetes/admin.conf
+ values:
+ nodeSelector:
+ openstack-control-plane: enabled
+ serviceMonitor:
+ enabled: true
+ namespace: monitoring
+ additionalLabels:
+ release: kube-prometheus-stack
+ relabelings:
+ - sourceLabels: ["__meta_kubernetes_pod_name"]
+ targetLabel: "instance"
+ - regex: "^(container|endpoint|namespace|pod|service)$"
+ action: "labeldrop"
diff --git a/tox.ini b/tox.ini
index feeae86..75f7b62 100644
--- a/tox.ini
+++ b/tox.ini
@@ -17,8 +17,16 @@
skipsdist = True
[testenv]
-usedevelop = True
+skipsdist = True
passenv =
OS_*
TERM
- STACK_NAME
\ No newline at end of file
+ STACK_NAME
+
+[testenv:molecule]
+deps =
+ ansible
+ molecule==3.5.2
+ -rmolecule/default/requirements.txt
+commands =
+ molecule {posargs}
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index c089928..435207e 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -17,6 +17,9 @@
parent: vexxhost-tox-molecule
pre-run:
- zuul.d/playbooks/ansible-collection-atmosphere-tox-molecule/pre-run.yml
+ cleanup-run:
+ - zuul.d/playbooks/ansible-collection-atmosphere-tox-molecule/cleanup-run.yml
+ timeout: 3600
vars:
tox_environment:
STACK_NAME: "atmosphere-{{ zuul.build }}"
diff --git a/zuul.d/playbooks/ansible-collection-atmosphere-tox-molecule/cleanup-run.yml b/zuul.d/playbooks/ansible-collection-atmosphere-tox-molecule/cleanup-run.yml
new file mode 100644
index 0000000..66f8e4b
--- /dev/null
+++ b/zuul.d/playbooks/ansible-collection-atmosphere-tox-molecule/cleanup-run.yml
@@ -0,0 +1,18 @@
+# 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.
+
+- hosts: all
+ tasks:
+ - name: Destroy the Molecule environment
+ shell: tox -e molecule -- destroy --all