From 63ea98533d612051747ebc97b8c10fcaa76d3fc0 Mon Sep 17 00:00:00 2001 From: Mingyuan Qi Date: Mon, 15 Apr 2019 14:29:18 +0800 Subject: [PATCH] Generate ironic overrides for helm chart Generate ironic network configurations for ironic helm chart. Specific address pool, interface/port, datanetwork are required before applying stx-openstack if ironic label enabled. A network with ironic network type is required to identify the ironic interface/port and address pool. A flat datanetwork by default named 'ironic' will be considered as ironic tenant network. Story: 2004760 Task: 30048 Change-Id: I4a179abc1cd64f4d574c39e3c8ff83593fc7e470 Signed-off-by: Mingyuan Qi --- sysinv/sysinv/sysinv/setup.cfg | 1 + sysinv/sysinv/sysinv/sysinv/helm/base.py | 13 ++ sysinv/sysinv/sysinv/sysinv/helm/common.py | 1 + sysinv/sysinv/sysinv/sysinv/helm/ironic.py | 193 ++++++++++++++++++++- sysinv/sysinv/sysinv/sysinv/helm/nova.py | 11 ++ 5 files changed, 218 insertions(+), 1 deletion(-) diff --git a/sysinv/sysinv/sysinv/setup.cfg b/sysinv/sysinv/sysinv/setup.cfg index 7e54a84720..01d487e563 100644 --- a/sysinv/sysinv/sysinv/setup.cfg +++ b/sysinv/sysinv/sysinv/setup.cfg @@ -105,6 +105,7 @@ systemconfig.helm_plugins.stx_openstack = 021_barbican = sysinv.helm.barbican:BarbicanHelm 022_keystone-api-proxy = sysinv.helm.keystone_api_proxy:KeystoneApiProxyHelm 023_ceph-rgw = sysinv.helm.swift:SwiftHelm + 024_ironic = sysinv.helm.ironic:IronicHelm sysinv.agent.lldp.drivers = lldpd = sysinv.agent.lldp.drivers.lldpd.driver:SysinvLldpdAgentDriver diff --git a/sysinv/sysinv/sysinv/sysinv/helm/base.py b/sysinv/sysinv/sysinv/sysinv/helm/base.py index 7a1057d833..1536d9d5ef 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/base.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/base.py @@ -205,6 +205,19 @@ class BaseHelm(object): cpus.append(c) return cpus + def _is_labeled(self, k, v): + """ + Check whether the label key value pair are set + """ + if self.dbapi is None: + return False + label_list = self.dbapi.label_get_all() + for label in label_list: + if label.label_key == k: + if label.label_value == v: + return True + return False + def get_namespaces(self): """ Return list of namespaces supported by this chart diff --git a/sysinv/sysinv/sysinv/sysinv/helm/common.py b/sysinv/sysinv/sysinv/sysinv/helm/common.py index 7463c1907b..e3c469e844 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/common.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/common.py @@ -50,6 +50,7 @@ LABEL_CONTROLLER = 'openstack-control-plane' LABEL_COMPUTE_LABEL = 'openstack-compute-node' LABEL_OPENVSWITCH = 'openvswitch' LABEL_REMOTE_STORAGE = 'remote-storage' +LABEL_IRONIC = 'openstack-ironic' # Label values LABEL_VALUE_ENABLED = 'enabled' diff --git a/sysinv/sysinv/sysinv/sysinv/helm/ironic.py b/sysinv/sysinv/sysinv/sysinv/helm/ironic.py index 6796df46dc..15e7bb92de 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/ironic.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/ironic.py @@ -16,11 +16,65 @@ class IronicHelm(openstack.OpenstackBaseHelm): CHART = constants.HELM_CHART_IRONIC - SERVICE_NAME = constants.HELM_CHART_IRONIC + SERVICE_NAME = 'ironic' + SERVICE_USERS = ['glance'] + AUTH_USERS = ['ironic'] + + def get_meta_overrides(self, namespace, app_name=None, mode=None): + + def _meta_overrides(): + if (self._num_controllers() >= 2 and + self._is_labeled(common.LABEL_IRONIC, 'enabled')): + # If there are fewer than 2 controllers or openstack-ironic + # label was not set, ironic chart won't be added to + # openstack-compute-kit chartgroup + return { + 'schema': 'armada/ChartGroup/v1', + 'metadata': { + 'schema': 'metadata/Document/v1', + 'name': 'openstack-compute-kit', + }, + 'data': { + 'description': + 'Deploy nova/neutron/ironic,' + + 'as well as supporting services', + 'sequenced': False, + 'chart_group': [ + 'openstack-libvirt', + 'openstack-openvswitch', + 'openstack-nova', + 'openstack-nova-api-proxy', + 'openstack-neutron', + 'openstack-ironic', + ] + } + } + else: + return {} + + overrides = { + common.HELM_NS_OPENSTACK: _meta_overrides() + } + if namespace in self.SUPPORTED_NAMESPACES: + return overrides[namespace] + elif namespace: + raise exception.InvalidHelmNamespace(chart=self.CHART, + namespace=namespace) + else: + return overrides def get_overrides(self, namespace=None): overrides = { common.HELM_NS_OPENSTACK: { + 'manifests': self._get_ironic_manifests(), + 'pod': { + 'replicas': { + 'api': self._num_controllers(), + 'conductor': self._num_controllers() + } + }, + 'network': self._get_network_overrides(), + 'endpoints': self._get_endpoints_overrides() } } @@ -31,3 +85,140 @@ class IronicHelm(openstack.OpenstackBaseHelm): namespace=namespace) else: return overrides + + def _ironic_manifests(self, is_labeled): + manifests = { + 'configmap_bin': is_labeled, + 'configmap_etc': is_labeled, + 'deployment_api': is_labeled, + 'ingress_api': is_labeled, + 'job_bootstrap': is_labeled, + 'job_db_init': is_labeled, + 'job_db_sync': is_labeled, + 'job_image_repo_sync': is_labeled, + 'job_ks_endpoints': is_labeled, + 'job_ks_service': is_labeled, + 'job_ks_user': is_labeled, + 'job_manage_cleaning_network': is_labeled, + 'job_rabbit_init': is_labeled, + 'pdb_api': is_labeled, + 'secret_db': is_labeled, + 'secret_keystone': is_labeled, + 'secret_rabbitmq': is_labeled, + 'service_api': is_labeled, + 'service_ingress_api': is_labeled, + 'statefulset_conductor': is_labeled + } + return manifests + + def _get_ironic_manifests(self): + ironic_label = self._is_labeled(common.LABEL_IRONIC, 'enabled') + return self._ironic_manifests(ironic_label) + + def _get_endpoints_overrides(self): + overrides = { + 'identity': { + 'auth': self._get_endpoints_identity_overrides( + self.SERVICE_NAME, self.AUTH_USERS), + }, + 'oslo_cache': { + 'auth': { + 'memcache_secret_key': + self._get_common_password('auth_memcache_key') + } + }, + 'oslo_db': { + 'auth': self._get_endpoints_oslo_db_overrides( + self.SERVICE_NAME, self.AUTH_USERS) + }, + 'oslo_messaging': { + 'auth': self._get_endpoints_oslo_messaging_overrides( + self.SERVICE_NAME, self.AUTH_USERS) + }, + } + + # Service user passwords already exist in other chart overrides + for user in self.SERVICE_USERS: + overrides['identity']['auth'].update({ + user: { + 'region_name': self._region_name(), + 'password': self._get_or_generate_password( + user, common.HELM_NS_OPENSTACK, user) + } + }) + + return overrides + + def _get_interface_port_name(self, iface): + """ + Determine the port name of the underlying device. + """ + assert iface['iftype'] == constants.INTERFACE_TYPE_ETHERNET + port = self.dbapi.port_get_by_interface(iface.id) + if port: + return port[0]['name'] + + def _get_ironic_port(self): + ironic_port = '' + if self.dbapi is None: + return ironic_port + # find the first interface with ironic network type + networks = self.dbapi.networks_get_by_type( + constants.NETWORK_TYPE_IRONIC) + for network in networks: + interface = self.dbapi.iinterface_get_by_network(network.name) + if interface: + # get first interface as ironic port + ironic_port = self._get_interface_port_name(interface[0]) + if ironic_port: + break + return ironic_port + + def _get_ironic_addrpool(self): + ironic_addrpool = {} + if self.dbapi is None: + return ironic_addrpool + networks = self.dbapi.networks_get_by_type( + constants.NETWORK_TYPE_IRONIC) + for network in networks: + addrpool = self.dbapi.address_pool_get(network.pool_uuid) + if addrpool: + ironic_addrpool['cidr'] = str(addrpool.network) + \ + '/' + str(addrpool.prefix) + ironic_addrpool['gateway'] = str(addrpool.gateway_address) + ironic_addrpool['start'] = str(addrpool.ranges[0][0]) + ironic_addrpool['end'] = str(addrpool.ranges[0][1]) + break + return ironic_addrpool + + # retrieve ironic network settings from address pools, + # ironic ethernet port name from interfaces, + # and ironic provider network from data networks. + # + # NOTE: Different ethernet port name for ironic conductor not supported. + # Currently the name of ironic port should be the same on each + # controllers to support HA, otherwise the initialization + # of ironic-conductor-pxe would be failed. It's a limitation + # from openstack-helm/ironic that ironic conductors use same + # configuration file for init. + def _get_network_overrides(self): + ironic_addrpool = self._get_ironic_addrpool() + gateway = ironic_addrpool.get('gateway', '') + cidr = ironic_addrpool.get('cidr', '') + start = ironic_addrpool.get('start', '') + end = ironic_addrpool.get('end', '') + + overrides = { + 'pxe': { + 'device': str(self._get_ironic_port()), + # User can define it's own tenant network name by + # 'system helm-override-update' to update this value + 'neutron_provider_network': 'ironic', + 'neutron_subnet_gateway': str(gateway), + 'neutron_subnet_cidr': str(cidr), + 'neutron_subnet_alloc_start': str(start), + 'neutron_subnet_alloc_end': str(end) + }, + } + + return overrides diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nova.py b/sysinv/sysinv/sysinv/sysinv/helm/nova.py index bd84a697e2..688b65615a 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nova.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nova.py @@ -64,6 +64,7 @@ class NovaHelm(openstack.OpenstackBaseHelm): self._get_or_generate_ssh_keys(self.SERVICE_NAME, common.HELM_NS_OPENSTACK) overrides = { common.HELM_NS_OPENSTACK: { + 'manifests': self._get_compute_ironic_manifests(), 'pod': { 'mounts': { 'nova_compute': { @@ -132,6 +133,16 @@ class NovaHelm(openstack.OpenstackBaseHelm): }) return overrides + def _compute_ironic_manifests(self, is_labeled): + manifests = { + 'statefulset_compute_ironic': is_labeled + } + return manifests + + def _get_compute_ironic_manifests(self): + ironic_label = self._is_labeled(common.LABEL_IRONIC, 'enabled') + return self._compute_ironic_manifests(ironic_label) + def _get_endpoints_overrides(self): overrides = { 'identity': {