From 3cd4032f55f5f52317ffd9be84c30ffcb9a1da06 Mon Sep 17 00:00:00 2001 From: Robert Church Date: Sun, 21 Jul 2019 17:41:24 -0400 Subject: [PATCH] Provide an API to control enabling/disabling application charts Extend the helm_charts API to support an enable attribute. This attribute is set on application upload and stored in the existing system_overrides element of the helm_overrides table. Changes include - Add application metadata support for disabling charts on application upload. - Add the system helm-chart-attribute-modify command to allow enabling and disabling charts from the command-line. This removes the current implementation of adding a faux label via the system host-label-assign command to enable and disable charts. - Add a --long option to helm-override-list to enable easy viewing of what charts are enabled for a given application - Enhance the ArmadaManifestOperator to make this a base class for application specific operator classes. Introduce classes for the stx-openstack and platform-integ-apps manifests with specific knowledge of the charts and chart groups within each class. - Use stevedore to load the application specific manifest operators. This will allow future packaging of manifest operators with new application tarballs. - Move the helm chart definition from the common/constants.py to helm/common.py. This limits helm/armada specific data leakage outside of the helm directory, which we may carve out of sysinv in the future. - Clean up the code related to the faux labels: LABEL_IRONIC, LABEL_BARBICAN, and LABEL_TELEMETRY - Rework the manifest update code in the plugins to include checks for if the chart for a given application has been disabled. Change-Id: If284f622ceac48c4ffd74e7022fdd390971d0fd8 Closes-Bug: #1833746 Depends-On: I418f0fe4978946a44e512c3025817fb27216c078 Signed-off-by: Robert Church --- .../centos/stx-openstack-helm.spec | 4 + .../stx-openstack-helm/files/metadata.yaml | 7 + .../cgts-client/cgtsclient/v1/helm.py | 19 +- .../cgts-client/cgtsclient/v1/helm_shell.py | 46 ++++- sysinv/sysinv/sysinv/setup.cfg | 5 + .../sysinv/api/controllers/v1/helm_charts.py | 76 +++++++- .../sysinv/sysinv/sysinv/common/constants.py | 37 ---- sysinv/sysinv/sysinv/sysinv/common/utils.py | 11 +- .../sysinv/sysinv/conductor/kube_app.py | 53 +++++- sysinv/sysinv/sysinv/sysinv/helm/aodh.py | 5 +- sysinv/sysinv/sysinv/sysinv/helm/barbican.py | 10 +- sysinv/sysinv/sysinv/sysinv/helm/base.py | 40 ++-- .../sysinv/sysinv/sysinv/helm/ceilometer.py | 9 +- .../sysinv/sysinv/helm/ceph_pools_audit.py | 11 +- sysinv/sysinv/sysinv/sysinv/helm/cinder.py | 4 +- sysinv/sysinv/sysinv/sysinv/helm/common.py | 39 +++- sysinv/sysinv/sysinv/sysinv/helm/garbd.py | 40 ++-- sysinv/sysinv/sysinv/sysinv/helm/glance.py | 6 +- sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py | 5 +- sysinv/sysinv/sysinv/sysinv/helm/heat.py | 5 +- sysinv/sysinv/sysinv/sysinv/helm/helm.py | 55 ++++-- .../sysinv/sysinv/sysinv/helm/helm_toolkit.py | 3 +- sysinv/sysinv/sysinv/sysinv/helm/horizon.py | 6 +- sysinv/sysinv/sysinv/sysinv/helm/ingress.py | 2 +- sysinv/sysinv/sysinv/sysinv/helm/ironic.py | 59 ++---- sysinv/sysinv/sysinv/sysinv/helm/keystone.py | 4 +- .../sysinv/sysinv/helm/keystone_api_proxy.py | 27 ++- sysinv/sysinv/sysinv/sysinv/helm/libvirt.py | 5 +- sysinv/sysinv/sysinv/sysinv/helm/magnum.py | 5 +- .../helm/{manifest.py => manifest_base.py} | 80 ++------ .../sysinv/sysinv/helm/manifest_generic.py | 32 ++++ .../sysinv/sysinv/helm/manifest_openstack.py | 178 ++++++++++++++++++ .../sysinv/sysinv/helm/manifest_platform.py | 43 +++++ sysinv/sysinv/sysinv/sysinv/helm/mariadb.py | 3 +- sysinv/sysinv/sysinv/sysinv/helm/memcached.py | 2 +- sysinv/sysinv/sysinv/sysinv/helm/neutron.py | 4 +- .../sysinv/sysinv/helm/nginx_ports_control.py | 3 +- sysinv/sysinv/sysinv/sysinv/helm/nova.py | 19 +- .../sysinv/sysinv/helm/nova_api_proxy.py | 9 +- sysinv/sysinv/sysinv/sysinv/helm/openstack.py | 35 +++- .../sysinv/sysinv/sysinv/helm/openvswitch.py | 26 ++- sysinv/sysinv/sysinv/sysinv/helm/panko.py | 5 +- sysinv/sysinv/sysinv/sysinv/helm/placement.py | 5 +- sysinv/sysinv/sysinv/sysinv/helm/rabbitmq.py | 3 +- .../sysinv/sysinv/helm/rbd_provisioner.py | 13 +- sysinv/sysinv/sysinv/sysinv/helm/swift.py | 3 +- 46 files changed, 753 insertions(+), 308 deletions(-) create mode 100644 kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/files/metadata.yaml rename sysinv/sysinv/sysinv/sysinv/helm/{manifest.py => manifest_base.py} (87%) create mode 100644 sysinv/sysinv/sysinv/sysinv/helm/manifest_generic.py create mode 100644 sysinv/sysinv/sysinv/sysinv/helm/manifest_openstack.py create mode 100644 sysinv/sysinv/sysinv/sysinv/helm/manifest_platform.py diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec index 459dfc575d..a90c1f5673 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec @@ -1,5 +1,6 @@ %global helm_folder /usr/lib/helm %global armada_folder /usr/lib/armada +%global app_folder /usr/lib/application %global toolkit_version 0.1.0 %global helmchart_version 0.1.0 @@ -70,6 +71,8 @@ rm ./helm-toolkit-%{toolkit_version}.tgz %install # helm_folder is created by openstack-helm-infra +install -d -m 755 ${RPM_BUILD_ROOT}%{app_folder} +install -p -D -m 755 files/metadata.yaml ${RPM_BUILD_ROOT}%{app_folder} install -d -m 755 ${RPM_BUILD_ROOT}%{helm_folder} install -p -D -m 755 *.tgz ${RPM_BUILD_ROOT}%{helm_folder} install -d -m 755 ${RPM_BUILD_ROOT}%{armada_folder} @@ -80,3 +83,4 @@ install -p -D -m 755 manifests/*.yaml ${RPM_BUILD_ROOT}%{armada_folder} %defattr(-,root,root,-) %{helm_folder}/* %{armada_folder}/* +%{app_folder}/* diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/files/metadata.yaml b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/files/metadata.yaml new file mode 100644 index 0000000000..53ad5ea576 --- /dev/null +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/files/metadata.yaml @@ -0,0 +1,7 @@ +disabled_charts: +- aodh +- barbican +- ceilometer +- gnocchi +- ironic +- panko diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm.py index c2c769309f..8dcc48539f 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm.py @@ -59,7 +59,7 @@ class HelmManager(base.Manager): This will return the end-user overrides for the specified chart. """ - body = {'flag': flag, 'values': override_values} + body = {'flag': flag, 'values': override_values, 'attributes': {}} return self._update(self._path(app) + '?name=' + name + '&namespace=' + namespace, body) @@ -74,3 +74,20 @@ class HelmManager(base.Manager): return self._delete(self._path(app) + '?name=' + name + '&namespace=' + namespace) + + def update_chart(self, app, name, namespace, attributes=None): + """Update non-override attributes for a given chart. + + :param app_name: name of application + :param name: name of the chart + :param namespace: namespace for the chart overrides + :param attributes: dict of chart attributes to be updated + + This will return the updated attributes for the specified chart. + """ + if not attributes: + attributes = {} + body = {'flag': None, 'values': {}, 'attributes': attributes} + return self._update(self._path(app) + + '?name=' + name + + '&namespace=' + namespace, body) diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm_shell.py index acb94d876e..68b6bfb2d8 100755 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm_shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/helm_shell.py @@ -39,11 +39,21 @@ def _find_overrides(cc, app, chart, namespace): @utils.arg('app', metavar='', help="Name of the application") +@utils.arg('-l', '--long', + action='store_true', + help='List additional fields in output') def do_helm_override_list(cc, args): """List system helm charts.""" app = app_utils._find_app(cc, args.app) charts = cc.helm.list_charts(app.name) - utils.print_list(charts, ['name', 'namespaces'], ['chart name', 'overrides namespaces'], sortby=0) + + keys = ['name', 'namespaces'] + labels = ['chart name', 'overrides namespaces'] + if args.long: + keys.append('enabled') + labels.append('chart enabled') + + utils.print_list(charts, keys, labels, sortby=0) @utils.arg('app', @@ -142,3 +152,37 @@ def do_helm_override_update(cc, args): chart = cc.helm.update_overrides(args.app, args.chart, args.namespace, flag, overrides) _print_helm_chart(chart) + + +@utils.arg('app', + metavar='', + help="Name of the application") +@utils.arg('chart', + metavar='', + help="Name of the chart") +@utils.arg('namespace', + metavar='', + help="Namespace of the chart") +@utils.arg('--enabled', + metavar='', + help="Chart enabled.") +def do_helm_chart_attribute_modify(cc, args): + """Modify helm chart attributes. + + This function is provided to modify system behaviorial attributes related to + a chart. This does not modify a chart nor does it modify chart overrides + which are managed through the helm-override-update command. + """ + + # Make sure the chart is present + app = app_utils._find_app(cc, args.app) + chart = _find_overrides(cc, app, args.chart, args.namespace) + + attributes = {} + if args.enabled is not None: + attributes.update({'enabled': args.enabled}) + + chart = cc.helm.update_chart(args.app, args.chart, args.namespace, + attributes) + + _print_helm_chart(chart) diff --git a/sysinv/sysinv/sysinv/setup.cfg b/sysinv/sysinv/sysinv/setup.cfg index e7a519c646..20332e34fb 100644 --- a/sysinv/sysinv/sysinv/setup.cfg +++ b/sysinv/sysinv/sysinv/setup.cfg @@ -105,6 +105,11 @@ systemconfig.helm_plugins.stx_openstack = 026_nginx-ports-control = sysinv.helm.nginx_ports_control:NginxPortsControlHelm 027_version_check = sysinv.helm.openstack_version_check:StxOpenstackVersionCheckHelm +systemconfig.armada.manifest_ops = + generic = sysinv.helm.manifest_generic:GenericArmadaManifestOperator + stx-openstack = sysinv.helm.manifest_openstack:OpenstackArmadaManifestOperator + platform-integ-apps = sysinv.helm.manifest_platform:PlatformArmadaManifestOperator + sysinv.agent.lldp.drivers = lldpd = sysinv.agent.lldp.drivers.lldpd.driver:SysinvLldpdAgentDriver ovs = sysinv.agent.lldp.drivers.ovs.driver:SysinvOVSAgentDriver diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/helm_charts.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/helm_charts.py index faed0f7e74..902a7c6066 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/helm_charts.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/helm_charts.py @@ -6,6 +6,7 @@ import pecan from pecan import rest +import six import yaml import wsme @@ -14,6 +15,7 @@ import wsmeext.pecan as wsme_pecan from sysinv import objects from sysinv.common import exception +from sysinv.helm import common from sysinv.openstack.common import log from sysinv.openstack.common.gettextutils import _ @@ -34,8 +36,24 @@ class HelmChartsController(rest.RestController): raise wsme.exc.ClientSideError(_("Unable to get the helm charts for " "application %s: %s" % (app_name, str(e)))) - charts = [{'name': chart, 'namespaces': namespaces[chart]} - for chart in namespaces] + charts = [] + for chart in namespaces: + enabled = [] + for ns in namespaces[chart]: + try: + app = objects.kube_app.get_by_name( + pecan.request.context, app_name) + db_chart = objects.helm_overrides.get_by_appid_name( + pecan.request.context, app.id, chart, ns) + except exception.KubeAppNotFound: + raise wsme.exc.ClientSideError( + _("Application %s not found." % app_name)) + + enabled.append(db_chart.system_overrides.get('enabled', + 'true')) + + charts.append({'name': chart, 'enabled': enabled, + 'namespaces': namespaces[chart]}) return {'charts': charts} @@ -62,7 +80,7 @@ class HelmChartsController(rest.RestController): user_overrides = None system_apps = pecan.request.rpcapi.get_helm_applications( - pecan.request.context) + pecan.request.context) if app_name in system_apps: # Get any system overrides for system app. try: @@ -92,8 +110,26 @@ class HelmChartsController(rest.RestController): combined_overrides = pecan.request.rpcapi.merge_overrides( pecan.request.context, file_overrides=file_overrides) + try: + attributes = {} + for k, v in six.iteritems(db_chart.system_overrides): + if k in common.HELM_CHART_ATTRS: + attributes.update({k: v}) + + if attributes: + attributes = yaml.safe_dump(attributes, + default_flow_style=False) + else: + attributes = None + + except Exception as e: + raise wsme.exc.ClientSideError( + _("Unable to get the helm chart attributes for chart %s under " + "Namespace %s: %s" % (name, namespace, str(e)))) + rpc_chart = {'name': name, 'namespace': namespace, + 'attributes': attributes, 'system_overrides': system_overrides, 'user_overrides': user_overrides, 'combined_overrides': combined_overrides} @@ -106,9 +142,9 @@ class HelmChartsController(rest.RestController): if not namespace: raise wsme.exc.ClientSideError(_("Namespace must be specified.")) - @wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text, + @wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text, wtypes.text, wtypes.text, wtypes.text, wtypes.text) - def patch(self, app_name, name, namespace, flag, values): + def patch(self, app_name, name, namespace, attributes, flag, values): """ Update user overrides. :param app_name: name of application @@ -117,6 +153,7 @@ class HelmChartsController(rest.RestController): :param flag: one of "reuse" or "reset", describes how to handle previous user overrides :param values: a dict of different types of user override values + :param attributes: a dict of non-overrides related chart attributes """ self.validate_name_and_namespace(name, namespace) @@ -154,21 +191,44 @@ class HelmChartsController(rest.RestController): file_overrides.insert(0, user_overrides) elif flag == 'reset': user_overrides = None - else: + elif values: raise wsme.exc.ClientSideError(_("Invalid flag: %s must be either " "'reuse' or 'reset'.") % flag) + # Form the response + chart = {'name': name, 'namespace': namespace} + if file_overrides or set_overrides: user_overrides = pecan.request.rpcapi.merge_overrides( pecan.request.context, file_overrides=file_overrides, set_overrides=set_overrides) + # update the response + chart.update({'user_overrides': user_overrides}) # save chart overrides back to DB db_chart.user_overrides = user_overrides db_chart.save() - chart = {'name': name, 'namespace': namespace, - 'user_overrides': user_overrides} + if attributes: + for k, v in six.iteritems(attributes): + if k not in common.HELM_CHART_ATTRS: + raise wsme.exc.ClientSideError( + _("Invalid chart attribute: %s must be one of [%s]") % + (k, ','.join(common.HELM_CHART_ATTRS))) + + if k == common.HELM_CHART_ATTR_ENABLED: + attributes[k] = attributes[k] in ['true', 'True'] + + # update the attribute changes + system_overrides = db_chart.system_overrides + system_overrides.update(attributes) + + # update the response + chart.update({'attributes': attributes}) + + # save attributes back to DB + db_chart.system_overrides = system_overrides + db_chart.save() return chart diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 6735ebf054..547974b59c 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -1302,47 +1302,10 @@ SYSTEM_SECURITY_FEATURE_SPECTRE_MELTDOWN_OPTS = { SYSTEM_SECURITY_FEATURE_SPECTRE_MELTDOWN_DEFAULT_OPTS = SYSTEM_SECURITY_FEATURE_SPECTRE_MELTDOWN_V1_OPTS -# Helm: Supported charts: -# These values match the names in the chart package's Chart.yaml -HELM_CHART_AODH = 'aodh' -HELM_CHART_BARBICAN = 'barbican' -HELM_CHART_CEILOMETER = 'ceilometer' -HELM_CHART_CINDER = 'cinder' -HELM_CHART_GARBD = 'garbd' -HELM_CHART_GLANCE = 'glance' -HELM_CHART_GNOCCHI = 'gnocchi' -HELM_CHART_HEAT = 'heat' -HELM_CHART_HORIZON = 'horizon' -HELM_CHART_INGRESS = 'ingress' -HELM_CHART_IRONIC = 'ironic' -HELM_CHART_KEYSTONE = 'keystone' -HELM_CHART_LIBVIRT = 'libvirt' -HELM_CHART_MAGNUM = 'magnum' -HELM_CHART_MARIADB = 'mariadb' -HELM_CHART_MEMCACHED = 'memcached' -HELM_CHART_NEUTRON = 'neutron' -HELM_CHART_NOVA = 'nova' -HELM_CHART_NOVA_API_PROXY = 'nova-api-proxy' -HELM_CHART_OPENVSWITCH = 'openvswitch' -HELM_CHART_PANKO = 'panko' -HELM_CHART_PLACEMENT = 'placement' -HELM_CHART_RABBITMQ = 'rabbitmq' -HELM_CHART_RBD_PROVISIONER = 'rbd-provisioner' -HELM_CHART_CEPH_POOLS_AUDIT = 'ceph-pools-audit' -HELM_CHART_HELM_TOOLKIT = 'helm-toolkit' -HELM_CHART_KEYSTONE_API_PROXY = 'keystone-api-proxy' -HELM_CHART_SWIFT = 'ceph-rgw' -HELM_CHART_NGINX_PORTS_CONTROL = "nginx-ports-control" - # Helm: Supported application (aka chart bundles) HELM_APP_OPENSTACK = 'stx-openstack' HELM_APP_PLATFORM = 'platform-integ-apps' -HELM_APPS_SUPPORTED = [ - HELM_APP_OPENSTACK, - HELM_APP_PLATFORM, -] - # Apply mode for openstack app OPENSTACK_RESTORE_DB = 'restore_db' OPENSTACK_RESTORE_STORAGE = 'restore_storage' diff --git a/sysinv/sysinv/sysinv/sysinv/common/utils.py b/sysinv/sysinv/sysinv/sysinv/common/utils.py index e24edbf12f..19ee89c9aa 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/common/utils.py @@ -1914,9 +1914,14 @@ def find_metadata_file(path, metadata_file): app_name: app_version: patch_dependencies: - - - - - ... + - + - + ... + repo: - optional: defaults to HELM_REPO_FOR_APPS + disabled_charts: - optional: charts default to enabled + - + - + ... """ app_name = '' app_version = '' diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py index feaef90311..826f4f74e2 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py @@ -18,6 +18,7 @@ import pwd import re import ruamel.yaml as yaml import shutil +import six import subprocess import threading import time @@ -39,7 +40,6 @@ from sysinv.common import utils as cutils from sysinv.common.storage_backend_conf import K8RbdProvisioner from sysinv.helm import common from sysinv.helm import helm -from sysinv.helm import manifest from sysinv.helm import utils as helm_utils from sysinv.openstack.common.gettextutils import _ @@ -770,28 +770,34 @@ class AppOperator(object): raise exception.KubeAppUploadFailure( name=app.name, version=app.version, reason="one or more charts failed validation.") - def _get_helm_repo_from_metadata(self, app): - """Get helm repo from application metadata + def _get_chart_data_from_metadata(self, app): + """Get chart related data from application metadata This extracts the helm repo from the application metadata where the chart should be loaded. + This also returns the list of charts that are disabled by default. + :param app: application """ repo = common.HELM_REPO_FOR_APPS - lfile = os.path.join(app.path, 'metadata.yaml') + disabled_charts = [] + lfile = os.path.join(app.path, constants.APP_METADATA_FILE) if os.path.exists(lfile) and os.path.getsize(lfile) > 0: with open(lfile, 'r') as f: try: y = yaml.safe_load(f) - repo = y['helm_repo'] + repo = y.get('helm_repo', common.HELM_REPO_FOR_APPS) + disabled_charts = y.get('disabled_charts', []) except KeyError: pass LOG.info("Application %s (%s) will load charts to chart repo %s" % ( app.name, app.version, repo)) - return repo + LOG.info("Application %s (%s) will disable charts %s by default" % ( + app.name, app.version, disabled_charts)) + return (repo, disabled_charts) def _upload_helm_charts(self, app): # Set env path for helm-upload execution @@ -801,7 +807,7 @@ class AppOperator(object): for r, f in cutils.get_files_matching(app.charts_dir, '.tgz')] orig_uid, orig_gid = get_app_install_root_path_ownership() - helm_repo = self._get_helm_repo_from_metadata(app) + (helm_repo, disabled_charts) = self._get_chart_data_from_metadata(app) try: # Temporarily change /scratch group ownership to sys_protected os.chown(constants.APP_INSTALL_ROOT_PATH, orig_uid, @@ -821,6 +827,37 @@ class AppOperator(object): finally: os.chown(constants.APP_INSTALL_ROOT_PATH, orig_uid, orig_gid) + # For system applications with plugin support, establish user override + # entries and disable charts based on application metadata. + db_app = self._dbapi.kube_app_get(app.name) + app_ns = self._helm.get_helm_application_namespaces(db_app.name) + for chart, namespaces in six.iteritems(app_ns): + for namespace in namespaces: + try: + db_chart = self._dbapi.helm_override_get( + db_app.id, chart, namespace) + except exception.HelmOverrideNotFound: + # Create it + try: + db_chart = self._dbapi.helm_override_create( + {'app_id': db_app.id, 'name': chart, + 'namespace': namespace}) + except Exception as e: + LOG.exception(e) + + # Since we are uploading a fresh application. Ensure that + # charts are disabled based on metadata + system_overrides = db_chart.system_overrides + system_overrides.update({common.HELM_CHART_ATTR_ENABLED: + chart not in disabled_charts}) + + try: + self._dbapi.helm_override_update( + db_app.id, chart, namespace, {'system_overrides': + system_overrides}) + except exception.HelmOverrideNotFound: + LOG.exception(e) + def _validate_labels(self, labels): expr = re.compile(r'[a-z0-9]([-a-z0-9]*[a-z0-9])') for label in labels: @@ -1185,7 +1222,7 @@ class AppOperator(object): return None # Get the armada manifest overrides files - manifest_op = manifest.ArmadaManifestOperator() + manifest_op = self._helm.get_armada_manifest_operator(app_name) armada_overrides = manifest_op.load_summary(overrides_dir) return (available_helm_overrides, armada_overrides) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/aodh.py b/sysinv/sysinv/sysinv/sysinv/helm/aodh.py index 2fbf890250..d4f3e24ea2 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/aodh.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/aodh.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,9 +15,9 @@ LOG = logging.getLogger(__name__) class AodhHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the aodh chart""" - CHART = constants.HELM_CHART_AODH + CHART = common.HELM_CHART_AODH - SERVICE_NAME = 'aodh' + SERVICE_NAME = common.HELM_CHART_AODH AUTH_USERS = ['aodh'] def get_overrides(self, namespace=None): diff --git a/sysinv/sysinv/sysinv/sysinv/helm/barbican.py b/sysinv/sysinv/sysinv/sysinv/helm/barbican.py index 62b1298ebf..edb7105a1d 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/barbican.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/barbican.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.helm import common from sysinv.helm import openstack @@ -13,14 +12,9 @@ from sysinv.helm import openstack class BarbicanHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the barbican chart""" - CHART = constants.HELM_CHART_BARBICAN + CHART = common.HELM_CHART_BARBICAN AUTH_USERS = ['barbican'] - SERVICE_NAME = constants.HELM_CHART_BARBICAN - - def execute_manifest_updates(self, operator, app_name=None): - if not self._is_labeled(common.LABEL_BARBICAN, 'enabled'): - operator.manifest_chart_groups_delete( - 'armada-manifest', 'openstack-barbican') + SERVICE_NAME = common.HELM_CHART_BARBICAN def get_overrides(self, namespace=None): overrides = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/base.py b/sysinv/sysinv/sysinv/sysinv/helm/base.py index 2825f81fa3..6c0dbcfe7e 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/base.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/base.py @@ -31,7 +31,7 @@ class BaseHelm(object): SUPPORTED_NAMESPACES = [] SUPPORTED_APP_NAMESPACES = {} SYSTEM_CONTROLLER_SERVICES = [ - constants.HELM_CHART_KEYSTONE_API_PROXY, + common.HELM_CHART_KEYSTONE_API_PROXY, ] def __init__(self, operator): @@ -200,19 +200,6 @@ 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 @@ -250,7 +237,7 @@ class BaseHelm(object): """ return True - def execute_manifest_updates(self, operator, app_name=None): + def execute_manifest_updates(self, operator): """ Update the elements of the armada manifest. @@ -262,7 +249,26 @@ class BaseHelm(object): armada/Manifest/v1, armada/ChartGroup/v1, armada/Chart/v1. :param operator: an instance of the ArmadaManifestOperator - :parameter app_name: application for which the specific actions are - taken """ pass + + def _is_enabled(self, app_name, chart_name, namespace): + """ + Check if the chart is enable at an application level + + :param app_name: Application name + :param chart_name: Chart supplied with the application + :param namespace: Namespace where the chart will be executed + + Returns true by default if an exception occurs as most charts are + enabled. + """ + try: + db_app = self.dbapi.kube_app_get(app_name) + db_chart = self.dbapi.helm_override_get(db_app.id, chart_name, namespace) + except exception.KubeAppNotFound: + return True + except exception.HelmOverrideNotFound: + return True + + return db_chart.system_overrides.get(common.HELM_CHART_ATTR_ENABLED, False) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py b/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py index 9f91d906c2..204fd1a8ce 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py @@ -17,16 +17,11 @@ LOG = logging.getLogger(__name__) class CeilometerHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the ceilometer chart""" - CHART = constants.HELM_CHART_CEILOMETER + CHART = common.HELM_CHART_CEILOMETER - SERVICE_NAME = 'ceilometer' + SERVICE_NAME = common.HELM_CHART_CEILOMETER AUTH_USERS = ['ceilometer'] - def execute_manifest_updates(self, operator, app_name=None): - if not self._is_labeled(common.LABEL_TELEMETRY, 'enabled'): - operator.manifest_chart_groups_delete( - 'armada-manifest', 'openstack-telemetry') - def get_overrides(self, namespace=None): overrides = { common.HELM_NS_OPENSTACK: { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/ceph_pools_audit.py b/sysinv/sysinv/sysinv/sysinv/helm/ceph_pools_audit.py index f68ddb3ad6..aaf6349162 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/ceph_pools_audit.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/ceph_pools_audit.py @@ -17,7 +17,7 @@ LOG = logging.getLogger(__name__) class CephPoolsAuditHelm(base.BaseHelm): """Class to encapsulate helm operations for the ceph-pools-audit chart""" - CHART = constants.HELM_CHART_CEPH_POOLS_AUDIT + CHART = common.HELM_CHART_CEPH_POOLS_AUDIT SUPPORTED_NAMESPACES = base.BaseHelm.SUPPORTED_NAMESPACES + \ [common.HELM_NS_STORAGE_PROVISIONER] SUPPORTED_APP_NAMESPACES = { @@ -27,6 +27,15 @@ class CephPoolsAuditHelm(base.BaseHelm): SERVICE_NAME = 'ceph-pools' + def execute_manifest_updates(self, operator): + # On application load this chart is enabled. Only disable if specified + # by the user + if not self._is_enabled(operator.APP, self.CHART, + common.HELM_NS_STORAGE_PROVISIONER): + operator.chart_group_chart_delete( + operator.CHART_GROUPS_LUT[self.CHART], + operator.CHARTS_LUT[self.CHART]) + def get_namespaces(self): return self.SUPPORTED_NAMESPACES diff --git a/sysinv/sysinv/sysinv/sysinv/helm/cinder.py b/sysinv/sysinv/sysinv/sysinv/helm/cinder.py index c338aeb0d8..8ffae920d2 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/cinder.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/cinder.py @@ -18,9 +18,9 @@ LOG = logging.getLogger(__name__) class CinderHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the cinder chart""" - CHART = constants.HELM_CHART_CINDER + CHART = common.HELM_CHART_CINDER - SERVICE_NAME = 'cinder' + SERVICE_NAME = common.HELM_CHART_CINDER SERVICE_TYPE = 'volume' AUTH_USERS = ['cinder'] diff --git a/sysinv/sysinv/sysinv/sysinv/helm/common.py b/sysinv/sysinv/sysinv/sysinv/helm/common.py index 8493e97fb8..28c6b518e3 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/common.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/common.py @@ -21,6 +21,42 @@ HELM_OVERRIDES_PATH = os.path.join(tsconfig.PLATFORM_PATH, 'helm', tsconfig.SW_V HELM_REPO_FOR_APPS = 'starlingx' HELM_REPO_FOR_PLATFORM = 'stx-platform' +# Supported chart attributes: +HELM_CHART_ATTR_ENABLED = 'enabled' +HELM_CHART_ATTRS = [HELM_CHART_ATTR_ENABLED] + +# Helm: Supported charts: +# These values match the names in the chart package's Chart.yaml +HELM_CHART_AODH = 'aodh' +HELM_CHART_BARBICAN = 'barbican' +HELM_CHART_CEILOMETER = 'ceilometer' +HELM_CHART_CINDER = 'cinder' +HELM_CHART_GARBD = 'garbd' +HELM_CHART_GLANCE = 'glance' +HELM_CHART_GNOCCHI = 'gnocchi' +HELM_CHART_HEAT = 'heat' +HELM_CHART_HORIZON = 'horizon' +HELM_CHART_INGRESS = 'ingress' +HELM_CHART_IRONIC = 'ironic' +HELM_CHART_KEYSTONE = 'keystone' +HELM_CHART_LIBVIRT = 'libvirt' +HELM_CHART_MAGNUM = 'magnum' +HELM_CHART_MARIADB = 'mariadb' +HELM_CHART_MEMCACHED = 'memcached' +HELM_CHART_NEUTRON = 'neutron' +HELM_CHART_NOVA = 'nova' +HELM_CHART_NOVA_API_PROXY = 'nova-api-proxy' +HELM_CHART_OPENVSWITCH = 'openvswitch' +HELM_CHART_PANKO = 'panko' +HELM_CHART_PLACEMENT = 'placement' +HELM_CHART_RABBITMQ = 'rabbitmq' +HELM_CHART_RBD_PROVISIONER = 'rbd-provisioner' +HELM_CHART_CEPH_POOLS_AUDIT = 'ceph-pools-audit' +HELM_CHART_HELM_TOOLKIT = 'helm-toolkit' +HELM_CHART_KEYSTONE_API_PROXY = 'keystone-api-proxy' +HELM_CHART_SWIFT = 'ceph-rgw' +HELM_CHART_NGINX_PORTS_CONTROL = "nginx-ports-control" + # Namespaces HELM_NS_CEPH = 'ceph' HELM_NS_DEFAULT = 'default' @@ -50,9 +86,6 @@ LABEL_CONTROLLER = 'openstack-control-plane' LABEL_COMPUTE_LABEL = 'openstack-compute-node' LABEL_OPENVSWITCH = 'openvswitch' LABEL_REMOTE_STORAGE = 'remote-storage' -LABEL_IRONIC = 'openstack-ironic' -LABEL_BARBICAN = 'openstack-barbican' -LABEL_TELEMETRY = 'openstack-telemetry' # Label values LABEL_VALUE_ENABLED = 'enabled' diff --git a/sysinv/sysinv/sysinv/sysinv/helm/garbd.py b/sysinv/sysinv/sysinv/sysinv/helm/garbd.py index 8d773f7a6d..c8adf1e80c 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/garbd.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/garbd.py @@ -20,9 +20,9 @@ class GarbdHelm(base.BaseHelm): # The service name is used to build the standard docker image location. # It is intentionally "mariadb" and not "garbd" as they both use the # same docker image. - SERVICE_NAME = 'mariadb' + SERVICE_NAME = common.HELM_CHART_MARIADB - CHART = constants.HELM_CHART_GARBD + CHART = common.HELM_CHART_GARBD SUPPORTED_NAMESPACES = \ base.BaseHelm.SUPPORTED_NAMESPACES + [common.HELM_NS_OPENSTACK] SUPPORTED_APP_NAMESPACES = { @@ -30,19 +30,29 @@ class GarbdHelm(base.BaseHelm): base.BaseHelm.SUPPORTED_NAMESPACES + [common.HELM_NS_OPENSTACK] } - def execute_manifest_updates(self, operator, app_name=None): - if app_name == constants.HELM_APP_OPENSTACK: - if (self._num_controllers() < 2 or - utils.is_aio_duplex_system(self.dbapi) or - (self._distributed_cloud_role() == - constants.DISTRIBUTED_CLOUD_ROLE_SYSTEMCONTROLLER)): - # If there are fewer than 2 controllers or we're on AIO-DX - # or we are on distributed cloud system controller - # we'll use a single mariadb server and so we don't want to - # run garbd. This will remove "openstack-garbd" from the - # charts in the openstack-mariadb chartgroup. - operator.chart_group_chart_delete('openstack-mariadb', - 'openstack-garbd') + def _is_enabled(self, app_name, chart_name, namespace): + # First, see if this chart is enabled by the user then adjust based on + # system conditions + enabled = super(GarbdHelm, self)._is_enabled( + app_name, chart_name, namespace) + + # If there are fewer than 2 controllers or we're on AIO-DX or we are on + # distributed cloud system controller, we'll use a single mariadb server + # and so we don't want to run garbd. + if enabled and (self._num_controllers() < 2 or + utils.is_aio_duplex_system(self.dbapi) or + (self._distributed_cloud_role() == + constants.DISTRIBUTED_CLOUD_ROLE_SYSTEMCONTROLLER)): + enabled = False + return enabled + + def execute_manifest_updates(self, operator): + # On application load this chart is enabled in the mariadb chart group + if not self._is_enabled(operator.APP, + self.CHART, common.HELM_NS_OPENSTACK): + operator.chart_group_chart_delete( + operator.CHART_GROUPS_LUT[self.CHART], + operator.CHARTS_LUT[self.CHART]) def get_overrides(self, namespace=None): overrides = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/glance.py b/sysinv/sysinv/sysinv/sysinv/helm/glance.py index 00475b3128..ac87a5b112 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/glance.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/glance.py @@ -22,9 +22,9 @@ RBD_STORE_USER = 'images' class GlanceHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the glance chart""" - CHART = constants.HELM_CHART_GLANCE + CHART = common.HELM_CHART_GLANCE - SERVICE_NAME = 'glance' + SERVICE_NAME = common.HELM_CHART_GLANCE SERVICE_TYPE = 'image' AUTH_USERS = ['glance'] @@ -65,7 +65,7 @@ class GlanceHelm(openstack.OpenstackBaseHelm): 'image': { 'host_fqdn_override': self._get_endpoints_host_fqdn_overrides( - constants.HELM_CHART_GLANCE), + common.HELM_CHART_GLANCE), 'scheme': self._get_endpoints_scheme_public_overrides(), 'port': self._get_endpoints_port_api_public_overrides(), }, diff --git a/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py b/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py index 9d01f0220f..66da0fea6b 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,9 +15,9 @@ LOG = logging.getLogger(__name__) class GnocchiHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the gnocchi chart""" - CHART = constants.HELM_CHART_GNOCCHI + CHART = common.HELM_CHART_GNOCCHI - SERVICE_NAME = 'gnocchi' + SERVICE_NAME = common.HELM_CHART_GNOCCHI AUTH_USERS = ['gnocchi'] def get_overrides(self, namespace=None): diff --git a/sysinv/sysinv/sysinv/sysinv/helm/heat.py b/sysinv/sysinv/sysinv/sysinv/helm/heat.py index 3660c8b3a5..f067688061 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/heat.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/heat.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,9 +15,9 @@ LOG = logging.getLogger(__name__) class HeatHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the heat chart""" - CHART = constants.HELM_CHART_HEAT + CHART = common.HELM_CHART_HEAT - SERVICE_NAME = constants.HELM_CHART_HEAT + SERVICE_NAME = common.HELM_CHART_HEAT AUTH_USERS = ['heat', 'heat_trustee', 'heat_stack_user'] def get_overrides(self, namespace=None): diff --git a/sysinv/sysinv/sysinv/sysinv/helm/helm.py b/sysinv/sysinv/sysinv/sysinv/helm/helm.py index 940bda8450..73d0b022f8 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/helm.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/helm.py @@ -17,12 +17,10 @@ import yaml from six import iteritems from stevedore import extension -from sysinv.common import constants from sysinv.common import exception from sysinv.common import utils from sysinv.openstack.common import log as logging from sysinv.helm import common -from sysinv.helm import manifest LOG = logging.getLogger(__name__) @@ -66,6 +64,32 @@ class HelmOperator(object): # dict containing sequence of helm charts per app self.helm_system_applications = self.get_helm_applications() + # dict containing Armada manifest operators per app + self.armada_manifest_operators = self.load_armada_manifest_operators() + + def load_armada_manifest_operators(self): + """Build a dictionary of armada manifest operators""" + + operators_dict = {} + + armada_manifest_operators = extension.ExtensionManager( + namespace='systemconfig.armada.manifest_ops', + invoke_on_load=True, invoke_args=()) + + for op in armada_manifest_operators: + operators_dict[op.name] = op.obj + + return operators_dict + + def get_armada_manifest_operator(self, app_name): + """Return a manifest operator based on app name""" + + if app_name in self.armada_manifest_operators: + manifest_op = self.armada_manifest_operators[app_name] + else: + manifest_op = self.armada_manifest_operators['generic'] + return manifest_op + def get_helm_applications(self): """Build a dictionary of supported helm applications""" @@ -482,9 +506,9 @@ class HelmOperator(object): LOG.exception("Application %s not found." % app_name) raise - # Get a manifest operator to provide a single point of manipulation for - # the chart, chart group and manifest schemas - manifest_op = manifest.ArmadaManifestOperator() + # Get a manifest operator to provide a single point of + # manipulation for the chart, chart group and manifest schemas + manifest_op = self.get_armada_manifest_operator(app_name) # Load the manifest into the operator armada_manifest = utils.generate_armada_manifest_filename_abs( @@ -544,11 +568,10 @@ class HelmOperator(object): # Update manifest docs based on the plugin directives if chart_name in self.chart_operators: self.chart_operators[chart_name].execute_manifest_updates( - manifest_op, app_name) + manifest_op) # Update the manifest based on platform conditions - manifest.platform_mode_manifest_updates( - self.dbapi, manifest_op, app_name, mode) + manifest_op.platform_mode_manifest_updates(self.dbapi, mode) else: # Generic applications @@ -686,7 +709,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_keystone_auth_data(self): - keystone_operator = self.chart_operators[constants.HELM_CHART_KEYSTONE] + keystone_operator = self.chart_operators[common.HELM_CHART_KEYSTONE] auth_data = { 'admin_user_name': keystone_operator.get_admin_user_name(), @@ -703,7 +726,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_nova_endpoint_data(self): - nova_operator = self.chart_operators[constants.HELM_CHART_NOVA] + nova_operator = self.chart_operators[common.HELM_CHART_NOVA] endpoint_data = { 'endpoint_override': 'http://nova-api.openstack.svc.cluster.local:8774', @@ -714,7 +737,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_nova_oslo_messaging_data(self): - nova_operator = self.chart_operators[constants.HELM_CHART_NOVA] + nova_operator = self.chart_operators[common.HELM_CHART_NOVA] endpoints_overrides = nova_operator._get_endpoints_overrides() auth_data = { 'host': @@ -734,7 +757,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_cinder_endpoint_data(self): - cinder_operator = self.chart_operators[constants.HELM_CHART_CINDER] + cinder_operator = self.chart_operators[common.HELM_CHART_CINDER] endpoint_data = { 'region_name': cinder_operator.get_region_name(), @@ -747,7 +770,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_glance_endpoint_data(self): - glance_operator = self.chart_operators[constants.HELM_CHART_GLANCE] + glance_operator = self.chart_operators[common.HELM_CHART_GLANCE] endpoint_data = { 'region_name': glance_operator.get_region_name(), @@ -760,7 +783,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_neutron_endpoint_data(self): - neutron_operator = self.chart_operators[constants.HELM_CHART_NEUTRON] + neutron_operator = self.chart_operators[common.HELM_CHART_NEUTRON] endpoint_data = { 'region_name': neutron_operator.get_region_name(), @@ -769,7 +792,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_heat_endpoint_data(self): - heat_operator = self.chart_operators[constants.HELM_CHART_HEAT] + heat_operator = self.chart_operators[common.HELM_CHART_HEAT] endpoint_data = { 'region_name': heat_operator.get_region_name(), @@ -779,7 +802,7 @@ class HelmOperatorData(HelmOperator): @helm_context def get_ceilometer_endpoint_data(self): ceilometer_operator = \ - self.chart_operators[constants.HELM_CHART_CEILOMETER] + self.chart_operators[common.HELM_CHART_CEILOMETER] endpoint_data = { 'region_name': ceilometer_operator.get_region_name(), diff --git a/sysinv/sysinv/sysinv/sysinv/helm/helm_toolkit.py b/sysinv/sysinv/sysinv/sysinv/helm/helm_toolkit.py index 9e57d09cc4..f448f9360a 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/helm_toolkit.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/helm_toolkit.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,7 +15,7 @@ LOG = logging.getLogger(__name__) class HelmToolkitHelm(base.BaseHelm): """Class to encapsulate helm operations for the helm toolkit""" - CHART = constants.HELM_CHART_HELM_TOOLKIT + CHART = common.HELM_CHART_HELM_TOOLKIT SUPPORTED_NAMESPACES = [ common.HELM_NS_HELM_TOOLKIT, ] diff --git a/sysinv/sysinv/sysinv/sysinv/helm/horizon.py b/sysinv/sysinv/sysinv/sysinv/helm/horizon.py index 280d40a187..1373299458 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/horizon.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/horizon.py @@ -16,9 +16,9 @@ LOG = logging.getLogger(__name__) class HorizonHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the horizon chart""" - CHART = constants.HELM_CHART_HORIZON + CHART = common.HELM_CHART_HORIZON - SERVICE_NAME = 'horizon' + SERVICE_NAME = common.HELM_CHART_HORIZON def get_overrides(self, namespace=None): overrides = { @@ -52,7 +52,7 @@ class HorizonHelm(openstack.OpenstackBaseHelm): 'dashboard': { 'host_fqdn_override': self._get_endpoints_host_fqdn_overrides( - constants.HELM_CHART_HORIZON), + common.HELM_CHART_HORIZON), 'port': self._get_endpoints_port_api_public_overrides(), 'scheme': self._get_endpoints_scheme_public_overrides(), }, diff --git a/sysinv/sysinv/sysinv/sysinv/helm/ingress.py b/sysinv/sysinv/sysinv/sysinv/helm/ingress.py index 78c1d2baff..99eed1b9a6 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/ingress.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/ingress.py @@ -16,7 +16,7 @@ LOG = logging.getLogger(__name__) class IngressHelm(base.BaseHelm): """Class to encapsulate helm operations for the ingress chart""" - CHART = constants.HELM_CHART_INGRESS + CHART = common.HELM_CHART_INGRESS SUPPORTED_NAMESPACES = base.BaseHelm.SUPPORTED_NAMESPACES + [ common.HELM_NS_KUBE_SYSTEM, diff --git a/sysinv/sysinv/sysinv/sysinv/helm/ironic.py b/sysinv/sysinv/sysinv/sysinv/helm/ironic.py index d5cb484385..20abd1e21f 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/ironic.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/ironic.py @@ -14,25 +14,33 @@ from sysinv.helm import openstack class IronicHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the ironic chart""" - CHART = constants.HELM_CHART_IRONIC + CHART = common.HELM_CHART_IRONIC - SERVICE_NAME = 'ironic' + SERVICE_NAME = common.HELM_CHART_IRONIC SERVICE_USERS = ['glance'] AUTH_USERS = ['ironic'] - def execute_manifest_updates(self, operator, app_name=None): - 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 - operator.chart_group_chart_insert('openstack-compute-kit', - 'openstack-ironic') + def _is_enabled(self, app_name, chart_name, namespace): + # First, see if this chart is enabled by the user then adjust based on + # system conditions + enabled = super(IronicHelm, self)._is_enabled(app_name, + chart_name, namespace) + if enabled and self._num_controllers() < 2: + enabled = False + return enabled + + def execute_manifest_updates(self, operator): + # On application load, this chart is disabled in the metadata. Insert as + # needed. + if self._is_enabled(operator.APP, + self.CHART, common.HELM_NS_OPENSTACK): + operator.chart_group_chart_insert( + operator.CHART_GROUPS_LUT[self.CHART], + operator.CHARTS_LUT[self.CHART]) def get_overrides(self, namespace=None): overrides = { common.HELM_NS_OPENSTACK: { - 'manifests': self._get_ironic_manifests(), 'pod': { 'replicas': { 'api': self._num_controllers(), @@ -52,35 +60,6 @@ class IronicHelm(openstack.OpenstackBaseHelm): 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': { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/keystone.py b/sysinv/sysinv/sysinv/sysinv/helm/keystone.py index a9d6a18542..52a445978e 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/keystone.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/keystone.py @@ -22,9 +22,9 @@ OPENSTACK_PASSWORD_RULES_FILE = '/etc/keystone/password-rules.conf' class KeystoneHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the keystone chart""" - CHART = constants.HELM_CHART_KEYSTONE + CHART = common.HELM_CHART_KEYSTONE - SERVICE_NAME = constants.HELM_CHART_KEYSTONE + SERVICE_NAME = common.HELM_CHART_KEYSTONE SERVICE_PATH = '/v3' DEFAULT_DOMAIN_NAME = 'default' diff --git a/sysinv/sysinv/sysinv/sysinv/helm/keystone_api_proxy.py b/sysinv/sysinv/sysinv/sysinv/helm/keystone_api_proxy.py index accdaad37a..603a3c2862 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/keystone_api_proxy.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/keystone_api_proxy.py @@ -16,16 +16,29 @@ LOG = logging.getLogger(__name__) class KeystoneApiProxyHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the keystone api proxy chart""" - CHART = constants.HELM_CHART_KEYSTONE_API_PROXY + CHART = common.HELM_CHART_KEYSTONE_API_PROXY - SERVICE_NAME = constants.HELM_CHART_KEYSTONE_API_PROXY + SERVICE_NAME = common.HELM_CHART_KEYSTONE_API_PROXY DCORCH_SERVICE_NAME = 'dcorch' - def execute_manifest_updates(self, operator, app_name=None): - if (self._distributed_cloud_role() == - constants.DISTRIBUTED_CLOUD_ROLE_SYSTEMCONTROLLER): + def _is_enabled(self, app_name, chart_name, namespace): + # First, see if this chart is enabled by the user then adjust based on + # system conditions + enabled = super(KeystoneApiProxyHelm, self)._is_enabled( + app_name, chart_name, namespace) + if enabled and (self._distributed_cloud_role() != + constants.DISTRIBUTED_CLOUD_ROLE_SYSTEMCONTROLLER): + enabled = False + return enabled + + def execute_manifest_updates(self, operator): + # This chart group is not included by default in the manifest. Insert as + # needed. + if self._is_enabled(operator.APP, + self.CHART, common.HELM_NS_OPENSTACK): operator.manifest_chart_groups_insert( - 'armada-manifest', 'openstack-keystone-api-proxy') + operator.ARMADA_MANIFEST, + operator.CHART_GROUPS_LUT[self.CHART]) def get_overrides(self, namespace=None): overrides = { @@ -71,7 +84,7 @@ class KeystoneApiProxyHelm(openstack.OpenstackBaseHelm): 'keystone_api_proxy': { 'host_fqdn_override': self._get_endpoints_host_fqdn_overrides( - constants.HELM_CHART_KEYSTONE_API_PROXY), + common.HELM_CHART_KEYSTONE_API_PROXY), 'port': self._get_endpoints_port_api_public_overrides(), 'scheme': self._get_endpoints_scheme_public_overrides(), } diff --git a/sysinv/sysinv/sysinv/sysinv/helm/libvirt.py b/sysinv/sysinv/sysinv/sysinv/helm/libvirt.py index d5b280a64c..63282e710c 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/libvirt.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/libvirt.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,9 +15,9 @@ LOG = logging.getLogger(__name__) class LibvirtHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the libvirt chart""" - CHART = constants.HELM_CHART_LIBVIRT + CHART = common.HELM_CHART_LIBVIRT - SERVICE_NAME = 'libvirt' + SERVICE_NAME = common.HELM_CHART_LIBVIRT def get_overrides(self, namespace=None): overrides = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/magnum.py b/sysinv/sysinv/sysinv/sysinv/helm/magnum.py index 6a51a0df69..3af4655741 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/magnum.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/magnum.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.helm import common @@ -14,9 +13,9 @@ from sysinv.helm import openstack class MagnumHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the magnum chart""" - CHART = constants.HELM_CHART_MAGNUM + CHART = common.HELM_CHART_MAGNUM - SERVICE_NAME = constants.HELM_CHART_MAGNUM + SERVICE_NAME = common.HELM_CHART_MAGNUM def get_overrides(self, namespace=None): overrides = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/manifest.py b/sysinv/sysinv/sysinv/sysinv/helm/manifest_base.py similarity index 87% rename from sysinv/sysinv/sysinv/sysinv/helm/manifest.py rename to sysinv/sysinv/sysinv/sysinv/helm/manifest_base.py index 1c937b76dd..bdb3806228 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/manifest.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/manifest_base.py @@ -9,15 +9,15 @@ """ System inventory Armada manifest operator.""" +import abc import os import json import ruamel.yaml as yaml +import six import tempfile from glob import glob from six import iteritems -from sysinv.common import constants -from sysinv.common import exception from sysinv.openstack.common import log as logging LOG = logging.getLogger(__name__) @@ -45,6 +45,7 @@ FILE_SUFFIX = '-meta.yaml' SUMMARY_FILE = 'armada-overrides.yaml' +@six.add_metaclass(abc.ABCMeta) class ArmadaManifestOperator(object): def __init__(self, manifest_fqpn=None): @@ -386,6 +387,8 @@ class ArmadaManifestOperator(object): self.docs[KEY_DATA_CHART_GROUPS][manifest][KEY_DATA][KEY_DATA_CHART_GROUPS] = chart_group_list + self.updated[KEY_DATA_CHART_GROUPS].update([manifest]) + else: LOG.error("Cannot set the manifest chart_groups to an empty list") @@ -470,6 +473,8 @@ class ArmadaManifestOperator(object): self.docs[KEY_DATA_CHART_GROUP][chart_group][KEY_DATA][KEY_DATA_CHART_GROUP] = chart_list + self.updated[KEY_DATA_CHART_GROUP].update([chart_group]) + else: LOG.error("Cannot set the chart_group charts to an empty list") @@ -497,68 +502,11 @@ class ArmadaManifestOperator(object): # Not implemented... yet. pass + @abc.abstractmethod + def platform_mode_manifest_updates(self, dbapi, mode): + """ Update the application manifest based on the platform -def platform_mode_manifest_updates(dbapi, manifest_op, app_name, mode): - """ Update the application manifest based on the platform - - This is used for - - :param dbapi: DB api object - :param manifest_op: ArmadaManifestOperator for updating the application - manifest - :param app_name: application name - :param mode: mode to control how to apply the application manifest - """ - - if not app_name: - LOG.info("App is None. No platform mode based manifest updates taken.") - - elif app_name not in constants.HELM_APP_APPLY_MODES.keys(): - LOG.info("App %s is not supported. No platform mode based manifest " - "updates taken." % app_name) - - elif app_name == constants.HELM_APP_OPENSTACK: - - if mode == constants.OPENSTACK_RESTORE_DB: - # During application restore, first bring up - # MariaDB service. - manifest_op.manifest_chart_groups_set( - 'armada-manifest', - ['kube-system-ingress', - 'openstack-ingress', - 'openstack-mariadb']) - - elif mode == constants.OPENSTACK_RESTORE_STORAGE: - # After MariaDB data is restored, restore Keystone, - # Glance and Cinder. - manifest_op.manifest_chart_groups_set( - 'armada-manifest', - ['kube-system-ingress', - 'openstack-ingress', - 'openstack-mariadb', - 'openstack-memcached', - 'openstack-rabbitmq', - 'openstack-keystone', - 'openstack-glance', - 'openstack-cinder']) - - else: - # When mode is OPENSTACK_RESTORE_NORMAL or None, - # bring up all the openstack services. - try: - system = dbapi.isystem_get_one() - except exception.NotFound: - LOG.exception("System %s not found.") - raise - - if (system.distributed_cloud_role == - constants.DISTRIBUTED_CLOUD_ROLE_SYSTEMCONTROLLER): - # remove the chart_groups not needed in this configuration - manifest_op.manifest_chart_groups_delete( - 'armada-manifest', 'openstack-ceph-rgw') - manifest_op.manifest_chart_groups_delete( - 'armada-manifest', 'openstack-compute-kit') - manifest_op.manifest_chart_groups_delete( - 'armada-manifest', 'openstack-heat') - manifest_op.manifest_chart_groups_delete( - 'armada-manifest', 'openstack-telemetry') + :param dbapi: DB api object + :param mode: mode to control how to apply the application manifest + """ + pass diff --git a/sysinv/sysinv/sysinv/sysinv/helm/manifest_generic.py b/sysinv/sysinv/sysinv/sysinv/helm/manifest_generic.py new file mode 100644 index 0000000000..405868b2cf --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/helm/manifest_generic.py @@ -0,0 +1,32 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# All Rights Reserved. +# + +""" System inventory Armada manifest operator.""" + +from sysinv.helm import manifest_base as base +from sysinv.openstack.common import log as logging + +LOG = logging.getLogger(__name__) + + +class GenericArmadaManifestOperator(base.ArmadaManifestOperator): + + APP = None + ARMADA_MANIFEST = None + + CHART_GROUPS_LUT = {} + CHARTS_LUT = {} + + def platform_mode_manifest_updates(self, dbapi, mode): + """ Update the application manifest based on the platform + + :param dbapi: DB api object + :param mode: mode to control how to apply the application manifest + """ + pass diff --git a/sysinv/sysinv/sysinv/sysinv/helm/manifest_openstack.py b/sysinv/sysinv/sysinv/sysinv/helm/manifest_openstack.py new file mode 100644 index 0000000000..ffce7b4748 --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/helm/manifest_openstack.py @@ -0,0 +1,178 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# All Rights Reserved. +# + +""" System inventory Armada manifest operator.""" + +from sysinv.common import constants +from sysinv.common import exception +from sysinv.helm import manifest_base as base +from sysinv.helm.aodh import AodhHelm +from sysinv.helm.barbican import BarbicanHelm +from sysinv.helm.ceilometer import CeilometerHelm +from sysinv.helm.cinder import CinderHelm +from sysinv.helm.garbd import GarbdHelm +from sysinv.helm.glance import GlanceHelm +from sysinv.helm.gnocchi import GnocchiHelm +from sysinv.helm.heat import HeatHelm +from sysinv.helm.horizon import HorizonHelm +from sysinv.helm.ingress import IngressHelm +from sysinv.helm.ironic import IronicHelm +from sysinv.helm.keystone import KeystoneHelm +from sysinv.helm.keystone_api_proxy import KeystoneApiProxyHelm +from sysinv.helm.libvirt import LibvirtHelm +from sysinv.helm.magnum import MagnumHelm +from sysinv.helm.mariadb import MariadbHelm +from sysinv.helm.memcached import MemcachedHelm +from sysinv.helm.neutron import NeutronHelm +from sysinv.helm.nginx_ports_control import NginxPortsControlHelm +from sysinv.helm.nova import NovaHelm +from sysinv.helm.nova_api_proxy import NovaApiProxyHelm +from sysinv.helm.openvswitch import OpenvswitchHelm +from sysinv.helm.panko import PankoHelm +from sysinv.helm.placement import PlacementHelm +from sysinv.helm.rabbitmq import RabbitmqHelm +from sysinv.helm.swift import SwiftHelm +from sysinv.openstack.common import log as logging + +LOG = logging.getLogger(__name__) + + +class OpenstackArmadaManifestOperator(base.ArmadaManifestOperator): + + APP = constants.HELM_APP_OPENSTACK + ARMADA_MANIFEST = 'armada-manifest' + + CHART_INGRESS_KS = CHART_GROUP_INGRESS_KS = 'kube-system-ingress' + + CHART_GROUP_INGRESS_OS = 'openstack-ingress' + CHART_GROUP_MAGNUM = 'openstack-magnum' + CHART_GROUP_MARIADB = 'openstack-mariadb' + CHART_GROUP_MEMCACHED = 'openstack-memcached' + CHART_GROUP_RABBITMQ = 'openstack-rabbitmq' + CHART_GROUP_KEYSTONE = 'openstack-keystone' + CHART_GROUP_KS_API_PROXY = 'openstack-keystone-api-proxy' + CHART_GROUP_BARBICAN = 'openstack-barbican' + CHART_GROUP_GLANCE = 'openstack-glance' + CHART_GROUP_SWIFT = 'openstack-ceph-rgw' + CHART_GROUP_CINDER = 'openstack-cinder' + CHART_GROUP_COMPUTE_KIT = 'openstack-compute-kit' + CHART_GROUP_HEAT = 'openstack-heat' + CHART_GROUP_HORIZON = 'openstack-horizon' + CHART_GROUP_TELEMETRY = 'openstack-telemetry' + + CHART_GROUPS_LUT = { + AodhHelm.CHART: CHART_GROUP_TELEMETRY, + BarbicanHelm.CHART: CHART_GROUP_BARBICAN, + CeilometerHelm.CHART: CHART_GROUP_TELEMETRY, + CinderHelm.CHART: CHART_GROUP_CINDER, + GarbdHelm.CHART: CHART_GROUP_MARIADB, + GlanceHelm.CHART: CHART_GROUP_GLANCE, + GnocchiHelm.CHART: CHART_GROUP_TELEMETRY, + HeatHelm.CHART: CHART_GROUP_HEAT, + HorizonHelm.CHART: CHART_GROUP_HORIZON, + IngressHelm.CHART: CHART_GROUP_INGRESS_OS, + IronicHelm.CHART: CHART_GROUP_COMPUTE_KIT, + KeystoneHelm.CHART: CHART_GROUP_KEYSTONE, + KeystoneApiProxyHelm.CHART: CHART_GROUP_KS_API_PROXY, + LibvirtHelm.CHART: CHART_GROUP_COMPUTE_KIT, + MagnumHelm.CHART: CHART_GROUP_MAGNUM, + MariadbHelm.CHART: CHART_GROUP_MARIADB, + MemcachedHelm.CHART: CHART_GROUP_MEMCACHED, + NeutronHelm.CHART: CHART_GROUP_COMPUTE_KIT, + NginxPortsControlHelm.CHART: CHART_GROUP_INGRESS_OS, + NovaHelm.CHART: CHART_GROUP_COMPUTE_KIT, + NovaApiProxyHelm.CHART: CHART_GROUP_COMPUTE_KIT, + OpenvswitchHelm.CHART: CHART_GROUP_COMPUTE_KIT, + PankoHelm.CHART: CHART_GROUP_TELEMETRY, + PlacementHelm.CHART: CHART_GROUP_COMPUTE_KIT, + RabbitmqHelm.CHART: CHART_GROUP_RABBITMQ, + SwiftHelm.CHART: CHART_GROUP_SWIFT, + } + + CHARTS_LUT = { + AodhHelm.CHART: 'openstack-aodh', + BarbicanHelm.CHART: 'openstack-barbican', + CeilometerHelm.CHART: 'openstack-ceilometer', + CinderHelm.CHART: 'openstack-cinder', + GarbdHelm.CHART: 'openstack-garbd', + GlanceHelm.CHART: 'openstack-glance', + GnocchiHelm.CHART: 'openstack-gnocchi', + HeatHelm.CHART: 'openstack-heat', + HorizonHelm.CHART: 'openstack-horizon', + IngressHelm.CHART: 'openstack-ingress', + IronicHelm.CHART: 'openstack-ironic', + KeystoneHelm.CHART: 'openstack-keystone', + KeystoneApiProxyHelm.CHART: 'openstack-keystone-api-proxy', + LibvirtHelm.CHART: 'openstack-libvirt', + MagnumHelm.CHART: 'openstack-magnum', + MariadbHelm.CHART: 'openstack-mariadb', + MemcachedHelm.CHART: 'openstack-memcached', + NeutronHelm.CHART: 'openstack-neutron', + NginxPortsControlHelm.CHART: 'openstack-nginx-ports-control', + NovaHelm.CHART: 'openstack-nova', + NovaApiProxyHelm.CHART: 'openstack-nova-api-proxy', + OpenvswitchHelm.CHART: 'openstack-openvswitch', + PankoHelm.CHART: 'openstack-panko', + PlacementHelm.CHART: 'openstack-placement', + RabbitmqHelm.CHART: 'openstack-rabbitmq', + SwiftHelm.CHART: 'openstack-ceph-rgw', + } + + def platform_mode_manifest_updates(self, dbapi, mode): + """ Update the application manifest based on the platform + + This is used for + + :param dbapi: DB api object + :param mode: mode to control how to apply the application manifest + """ + + if mode == constants.OPENSTACK_RESTORE_DB: + # During application restore, first bring up + # MariaDB service. + self.manifest_chart_groups_set( + self.ARMADA_MANIFEST, + [self.CHART_GROUP_INGRESS_KS, + self.CHART_GROUP_INGRESS_OS, + self.CHART_GROUP_MARIADB]) + + elif mode == constants.OPENSTACK_RESTORE_STORAGE: + # After MariaDB data is restored, restore Keystone, + # Glance and Cinder. + self.manifest_chart_groups_set( + self.ARMADA_MANIFEST, + [self.CHART_GROUP_INGRESS_KS, + self.CHART_GROUP_INGRESS_OS, + self.CHART_GROUP_MARIADB, + self.CHART_GROUP_MEMCACHED, + self.CHART_GROUP_RABBITMQ, + self.CHART_GROUP_KEYSTONE, + self.CHART_GROUP_GLANCE, + self.CHART_GROUP_CINDER]) + + else: + # When mode is OPENSTACK_RESTORE_NORMAL or None, + # bring up all the openstack services. + try: + system = dbapi.isystem_get_one() + except exception.NotFound: + LOG.exception("System %s not found.") + raise + + if (system.distributed_cloud_role == + constants.DISTRIBUTED_CLOUD_ROLE_SYSTEMCONTROLLER): + # remove the chart_groups not needed in this configuration + self.manifest_chart_groups_delete( + self.ARMADA_MANIFEST, self.CHART_GROUP_SWIFT) + self.manifest_chart_groups_delete( + self.ARMADA_MANIFEST, self.CHART_GROUP_COMPUTE_KIT) + self.manifest_chart_groups_delete( + self.ARMADA_MANIFEST, self.CHART_GROUP_HEAT) + self.manifest_chart_groups_delete( + self.ARMADA_MANIFEST, self.CHART_GROUP_TELEMETRY) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/manifest_platform.py b/sysinv/sysinv/sysinv/sysinv/helm/manifest_platform.py new file mode 100644 index 0000000000..545f71ab90 --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/helm/manifest_platform.py @@ -0,0 +1,43 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# All Rights Reserved. +# + +""" System inventory Armada manifest operator.""" + +from sysinv.common import constants +from sysinv.helm import manifest_base as base +from sysinv.helm.ceph_pools_audit import CephPoolsAuditHelm +from sysinv.helm.rbd_provisioner import RbdProvisionerHelm +from sysinv.openstack.common import log as logging + +LOG = logging.getLogger(__name__) + + +class PlatformArmadaManifestOperator(base.ArmadaManifestOperator): + + APP = constants.HELM_APP_PLATFORM + ARMADA_MANIFEST = 'platform-integration-manifest' + + CHART_GROUP_CEPH = 'starlingx-ceph-charts' + CHART_GROUPS_LUT = { + CephPoolsAuditHelm.CHART: CHART_GROUP_CEPH, + RbdProvisionerHelm.CHART: CHART_GROUP_CEPH + } + + CHARTS_LUT = { + CephPoolsAuditHelm.CHART: 'kube-system-ceph-pools-audit', + RbdProvisionerHelm.CHART: 'kube-system-rbd-provisioner' + } + + def platform_mode_manifest_updates(self, dbapi, mode): + """ Update the application manifest based on the platform + + :param dbapi: DB api object + :param mode: mode to control how to apply the application manifest + """ + pass diff --git a/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py b/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py index a917c7fc14..4ab25b4080 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,7 +15,7 @@ LOG = logging.getLogger(__name__) class MariadbHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the mariadb chart""" - CHART = constants.HELM_CHART_MARIADB + CHART = common.HELM_CHART_MARIADB def _num_server_replicas(self): return self._num_controllers() diff --git a/sysinv/sysinv/sysinv/sysinv/helm/memcached.py b/sysinv/sysinv/sysinv/sysinv/helm/memcached.py index 936877693a..ffa7f562ad 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/memcached.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/memcached.py @@ -16,7 +16,7 @@ LOG = logging.getLogger(__name__) class MemcachedHelm(base.BaseHelm): """Class to encapsulate helm operations for the memcached chart""" - CHART = constants.HELM_CHART_MEMCACHED + CHART = common.HELM_CHART_MEMCACHED SUPPORTED_NAMESPACES = \ base.BaseHelm.SUPPORTED_NAMESPACES + [common.HELM_NS_OPENSTACK] SUPPORTED_APP_NAMESPACES = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/neutron.py b/sysinv/sysinv/sysinv/sysinv/helm/neutron.py index 708f14daac..0b68b5a79a 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/neutron.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/neutron.py @@ -20,9 +20,9 @@ SRIOV_NETWORK_TYPES = [constants.NETWORK_TYPE_PCI_SRIOV] class NeutronHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the neutron chart""" - CHART = constants.HELM_CHART_NEUTRON + CHART = common.HELM_CHART_NEUTRON - SERVICE_NAME = 'neutron' + SERVICE_NAME = common.HELM_CHART_NEUTRON AUTH_USERS = ['neutron'] SERVICE_USERS = ['nova'] diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nginx_ports_control.py b/sysinv/sysinv/sysinv/sysinv/helm/nginx_ports_control.py index aa74d9a03b..1835428b48 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nginx_ports_control.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nginx_ports_control.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,7 +15,7 @@ LOG = logging.getLogger(__name__) class NginxPortsControlHelm(base.BaseHelm): """Class to encapsulate helm operations for nginx-ports-control chart""" - CHART = constants.HELM_CHART_NGINX_PORTS_CONTROL + CHART = common.HELM_CHART_NGINX_PORTS_CONTROL SUPPORTED_NAMESPACES = \ base.BaseHelm.SUPPORTED_NAMESPACES + [common.HELM_NS_OPENSTACK] diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nova.py b/sysinv/sysinv/sysinv/sysinv/helm/nova.py index 201b379cd3..cbff69a713 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nova.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nova.py @@ -43,9 +43,9 @@ DEFAULT_NOVA_PCI_ALIAS = [ class NovaHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the nova chart""" - CHART = constants.HELM_CHART_NOVA + CHART = common.HELM_CHART_NOVA - SERVICE_NAME = 'nova' + SERVICE_NAME = common.HELM_CHART_NOVA AUTH_USERS = ['nova', ] SERVICE_USERS = ['neutron', 'ironic', 'placement'] NOVNCPROXY_SERVICE_NAME = 'novncproxy' @@ -125,15 +125,14 @@ 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) + ironic_operator = self._operator.chart_operators[ + common.HELM_CHART_IRONIC] + enabled = ironic_operator._is_enabled(constants.HELM_APP_OPENSTACK, + common.HELM_CHART_IRONIC, common.HELM_NS_OPENSTACK) + return { + 'statefulset_compute_ironic': enabled + } def _get_endpoints_overrides(self): overrides = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py b/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py index 2852907f86..101e119a71 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,9 +15,9 @@ LOG = logging.getLogger(__name__) class NovaApiProxyHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the nova chart""" - CHART = constants.HELM_CHART_NOVA_API_PROXY + CHART = common.HELM_CHART_NOVA_API_PROXY - SERVICE_NAME = 'nova-api-proxy' + SERVICE_NAME = common.HELM_CHART_NOVA_API_PROXY AUTH_USERS = ['nova'] def get_overrides(self, namespace=None): @@ -56,7 +55,7 @@ class NovaApiProxyHelm(openstack.OpenstackBaseHelm): def _get_endpoints_overrides(self): nova_service_name = self._operator.chart_operators[ - constants.HELM_CHART_NOVA].SERVICE_NAME + common.HELM_CHART_NOVA].SERVICE_NAME return { 'identity': { @@ -66,7 +65,7 @@ class NovaApiProxyHelm(openstack.OpenstackBaseHelm): 'compute': { 'host_fqdn_override': self._get_endpoints_host_fqdn_overrides( - constants.HELM_CHART_NOVA), + common.HELM_CHART_NOVA), 'port': self._get_endpoints_port_api_public_overrides(), 'scheme': self._get_endpoints_scheme_public_overrides(), }, diff --git a/sysinv/sysinv/sysinv/sysinv/helm/openstack.py b/sysinv/sysinv/sysinv/sysinv/helm/openstack.py index 334faa6dcb..24ac46bc2a 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/openstack.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/openstack.py @@ -70,7 +70,7 @@ class OpenstackBaseHelm(base.BaseHelm): def _get_admin_user_name(self): keystone_operator = self._operator.chart_operators[ - constants.HELM_CHART_KEYSTONE] + common.HELM_CHART_KEYSTONE] return keystone_operator.get_admin_user_name() def _get_identity_password(self, service, user): @@ -469,3 +469,36 @@ class OpenstackBaseHelm(base.BaseHelm): K8RbdProvisioner.get_user_secret_name({ 'name': constants.SB_DEFAULT_NAMES[constants.SB_TYPE_CEPH]}) } + + def execute_manifest_updates(self, operator): + """ + Update the elements of the armada manifest. + + This allows a helm chart plugin to use the ArmadaManifestOperator to + make dynamic structural changes to the application manifest based on the + current conditions in the platform + + Changes include updates to manifest documents for the following schemas: + armada/Manifest/v1, armada/ChartGroup/v1, armada/Chart/v1. + + :param operator: an instance of the ArmadaManifestOperator + """ + if not self._is_enabled(operator.APP, self.CHART, + common.HELM_NS_OPENSTACK): + operator.chart_group_chart_delete( + operator.CHART_GROUPS_LUT[self.CHART], + operator.CHARTS_LUT[self.CHART]) + + def _is_enabled(self, app_name, chart_name, namespace): + """ + Check if the chart is enable at a system level + + :param app_name: Application name + :param chart_name: Chart supplied with the application + :param namespace: Namespace where the chart will be executed + + Returns true by default if an exception occurs as most charts are + enabled. + """ + return super(OpenstackBaseHelm, self)._is_enabled( + app_name, chart_name, namespace) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/openvswitch.py b/sysinv/sysinv/sysinv/sysinv/helm/openvswitch.py index 94348ac17f..2950fc6ee5 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/openvswitch.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/openvswitch.py @@ -17,15 +17,27 @@ LOG = logging.getLogger(__name__) class OpenvswitchHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the openvswitch chart""" - CHART = constants.HELM_CHART_OPENVSWITCH + CHART = common.HELM_CHART_OPENVSWITCH - def execute_manifest_updates(self, operator, app_name=None): - if utils.get_vswitch_type(self.dbapi) == constants.VSWITCH_TYPE_NONE: - # add the openvswitch chart into computekit chart group + def _is_enabled(self, app_name, chart_name, namespace): + # First, see if this chart is enabled by the user then adjust based on + # system conditions + enabled = super(OpenvswitchHelm, self)._is_enabled( + app_name, chart_name, namespace) + if enabled and (utils.get_vswitch_type(self.dbapi) != + constants.VSWITCH_TYPE_NONE): + enabled = False + return enabled + + def execute_manifest_updates(self, operator): + # On application load, this chart in not included in the compute-kit + # chart group . Insert as needed. + if self._is_enabled(operator.APP, + self.CHART, common.HELM_NS_OPENSTACK): operator.chart_group_chart_insert( - 'openstack-compute-kit', - 'openstack-openvswitch', - before_chart='openstack-nova') + operator.CHART_GROUPS_LUT[self.CHART], + operator.CHARTS_LUT[self.CHART], + before_chart=operator.CHARTS_LUT[common.HELM_CHART_NOVA]) def get_overrides(self, namespace=None): overrides = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/panko.py b/sysinv/sysinv/sysinv/sysinv/helm/panko.py index 93cfd9a956..212289f6af 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/panko.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/panko.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,9 +15,9 @@ LOG = logging.getLogger(__name__) class PankoHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the panko chart""" - CHART = constants.HELM_CHART_PANKO + CHART = common.HELM_CHART_PANKO - SERVICE_NAME = 'panko' + SERVICE_NAME = common.HELM_CHART_PANKO AUTH_USERS = ['panko'] def get_overrides(self, namespace=None): diff --git a/sysinv/sysinv/sysinv/sysinv/helm/placement.py b/sysinv/sysinv/sysinv/sysinv/helm/placement.py index 177a236d0d..038784a2b4 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/placement.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/placement.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.helm import common from sysinv.helm import openstack @@ -13,9 +12,9 @@ from sysinv.helm import openstack class PlacementHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the placement chart""" - CHART = constants.HELM_CHART_PLACEMENT + CHART = common.HELM_CHART_PLACEMENT - SERVICE_NAME = 'placement' + SERVICE_NAME = common.HELM_CHART_PLACEMENT AUTH_USERS = ['placement'] def get_overrides(self, namespace=None): diff --git a/sysinv/sysinv/sysinv/sysinv/helm/rabbitmq.py b/sysinv/sysinv/sysinv/sysinv/helm/rabbitmq.py index 4b6281a54a..3743c62cd7 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/rabbitmq.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/rabbitmq.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging from sysinv.helm import common @@ -16,7 +15,7 @@ LOG = logging.getLogger(__name__) class RabbitmqHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the rabbitmq chart""" - CHART = constants.HELM_CHART_RABBITMQ + CHART = common.HELM_CHART_RABBITMQ def get_overrides(self, namespace=None): overrides = { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/rbd_provisioner.py b/sysinv/sysinv/sysinv/sysinv/helm/rbd_provisioner.py index 3a8b014241..c0905e8a4b 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/rbd_provisioner.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/rbd_provisioner.py @@ -18,7 +18,7 @@ LOG = logging.getLogger(__name__) class RbdProvisionerHelm(base.BaseHelm): """Class to encapsulate helm operations for the rbd-provisioner chart""" - CHART = constants.HELM_CHART_RBD_PROVISIONER + CHART = common.HELM_CHART_RBD_PROVISIONER SUPPORTED_NAMESPACES = base.BaseHelm.SUPPORTED_NAMESPACES + \ [common.HELM_NS_STORAGE_PROVISIONER] SUPPORTED_APP_NAMESPACES = { @@ -26,9 +26,18 @@ class RbdProvisionerHelm(base.BaseHelm): base.BaseHelm.SUPPORTED_NAMESPACES + [common.HELM_NS_STORAGE_PROVISIONER], } - SERVICE_NAME = 'rbd-provisioner' + SERVICE_NAME = common.HELM_CHART_RBD_PROVISIONER SERVICE_PORT_MON = 6789 + def execute_manifest_updates(self, operator): + # On application load this chart is enabled. Only disable if specified + # by the user + if not self._is_enabled(operator.APP, self.CHART, + common.HELM_NS_STORAGE_PROVISIONER): + operator.chart_group_chart_delete( + operator.CHART_GROUPS_LUT[self.CHART], + operator.CHARTS_LUT[self.CHART]) + def get_overrides(self, namespace=None): backends = self.dbapi.storage_backend_get_list() diff --git a/sysinv/sysinv/sysinv/sysinv/helm/swift.py b/sysinv/sysinv/sysinv/sysinv/helm/swift.py index 0dcc12b671..f6c63899cd 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/swift.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/swift.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging @@ -18,7 +17,7 @@ LOG = logging.getLogger(__name__) class SwiftHelm(openstack.OpenstackBaseHelm): """Class to encapsulate helm operations for the swift chart""" - CHART = constants.HELM_CHART_SWIFT + CHART = common.HELM_CHART_SWIFT SERVICE_NAME = 'swift' SERVICE_TYPE = 'object-store'