Dynamic helm plugins

This commit adds proper support for dynamically loading helm plugins,
to allow third-party helm plugins to be loaded.
The ordering of these dynamically-loaded helm plugins is based on the
name of the entry point, with the numerical prefix added to allow easy
control of plugin order.

Story: 2003909
Task: 29399

Change-Id: I27fec940d27e330854f45ba2088f415d917bf7ce
Signed-off-by: Joseph Richard <joseph.richard@windriver.com>
This commit is contained in:
Joseph Richard 2019-02-04 17:10:48 -05:00
parent bb33059717
commit c3ac460ac9
5 changed files with 88 additions and 136 deletions

View File

@ -74,32 +74,33 @@ systemconfig.puppet_plugins =
034_dockerdistribution = sysinv.puppet.dockerdistribution:DockerDistributionPuppet
099_service_parameter = sysinv.puppet.service_parameter:ServiceParamPuppet
systemconfig.helm_plugins =
aodh = sysinv.helm.aodh:AodhHelm
barbican = sysinv.helm.barbican:BarbicanHelm
ceilometer = sysinv.helm.ceilometer:CeilometerHelm
cinder = sysinv.helm.cinder:CinderHelm
garbd = sysinv.helm.garbd:GarbdHelm
glance = sysinv.helm.glance:GlanceHelm
gnocchi = sysinv.helm.gnocchi:GnocchiHelm
heat = sysinv.helm.heat:HeatHelm
horizon = sysinv.helm.horizon:HorizonHelm
ingress = sysinv.helm.ingress:IngressHelm
ironic = sysinv.helm.ironic:IronicHelm
keystone = sysinv.helm.keystone:KeystoneHelm
libvirt = sysinv.helm.libvirt:LibvirtHelm
magnum = sysinv.helm.magnum:MagnumHelm
mariadb = sysinv.helm.mariadb:MariadbHelm
memcached = sysinv.helm.memcached:MemcachedHelm
neutron = sysinv.helm.neutron:NeutronHelm
nova = sysinv.helm.nova:NovaHelm
nova-api-proxy = sysinv.helm.nova_api_proxy:NovaApiProxyHelm
openvswitch = sysinv.helm.openvswitch:OpenvswitchHelm
panko = sysinv.helm.panko:PankoHelm
rabbitmq = sysinv.helm.rabbitmq:RabbitmqHelm
rbd-provisioner = sysinv.helm.rbd_provisioner:RbdProvisionerHelm
ceph-pools-audit = sysinv.helm.ceph_pools_audit:CephPoolsAuditHelm
helm-toolkit = sysinv.helm.helm_toolkit:HelmToolkitHelm
systemconfig.helm_applications =
stx-openstack = systemconfig.helm_plugins.stx_openstack
systemconfig.helm_plugins.stx_openstack =
001_ingress = sysinv.helm.ingress:IngressHelm
002_rbd-provisioner = sysinv.helm.rbd_provisioner:RbdProvisionerHelm
003_ceph-pools-audit = sysinv.helm.ceph_pools_audit:CephPoolsAuditHelm
004_mariadb = sysinv.helm.mariadb:MariadbHelm
005_garbd = sysinv.helm.garbd:GarbdHelm
006_rabbitmq = sysinv.helm.rabbitmq:RabbitmqHelm
007_memcached = sysinv.helm.memcached:MemcachedHelm
008_keystone = sysinv.helm.keystone:KeystoneHelm
009_heat = sysinv.helm.heat:HeatHelm
010_horizon = sysinv.helm.horizon:HorizonHelm
011_glance = sysinv.helm.glance:GlanceHelm
012_openvswitch = sysinv.helm.openvswitch:OpenvswitchHelm
013_libvirt = sysinv.helm.libvirt:LibvirtHelm
014_neutron = sysinv.helm.neutron:NeutronHelm
015_nova = sysinv.helm.nova:NovaHelm
016_nova-api-proxy = sysinv.helm.nova_api_proxy:NovaApiProxyHelm
017_cinder = sysinv.helm.cinder:CinderHelm
018_gnocchi = sysinv.helm.gnocchi:GnocchiHelm
019_ceilometer = sysinv.helm.ceilometer:CeilometerHelm
020_panko = sysinv.helm.panko:PankoHelm
021_aodh = sysinv.helm.aodh:AodhHelm
022_helm-toolkit = sysinv.helm.helm_toolkit:HelmToolkitHelm
023_barbican = sysinv.helm.barbican:BarbicanHelm
sysinv.agent.lldp.drivers =
lldpd = sysinv.agent.lldp.drivers.lldpd.driver:SysinvLldpdAgentDriver

View File

@ -50,11 +50,7 @@ class HelmChartsController(rest.RestController):
pecan.request.context, name, namespace)
user_overrides = db_chart.user_overrides
except exception.HelmOverrideNotFound:
if name in constants.SUPPORTED_HELM_CHARTS:
user_overrides = ''
else:
# Unsupported/invalid chart name (and namespace)
raise wsme.exc.ClientSideError(_("Override not found."))
user_overrides = ''
# Get any system overrides.
try:
@ -109,15 +105,12 @@ class HelmChartsController(rest.RestController):
db_chart = objects.helm_overrides.get_by_name(
pecan.request.context, name, namespace)
except exception.HelmOverrideNotFound:
if name in constants.SUPPORTED_HELM_CHARTS:
pecan.request.dbapi.helm_override_create({
'name': name,
'namespace': namespace,
'user_overrides': ''})
db_chart = objects.helm_overrides.get_by_name(
pecan.request.context, name, namespace)
else:
raise
pecan.request.dbapi.helm_override_create({
'name': name,
'namespace': namespace,
'user_overrides': ''})
db_chart = objects.helm_overrides.get_by_name(
pecan.request.context, name, namespace)
if flag == 'reuse':
if db_chart.user_overrides is not None:

View File

@ -1461,33 +1461,6 @@ HELM_CHART_RBD_PROVISIONER = 'rbd-provisioner'
HELM_CHART_CEPH_POOLS_AUDIT = 'ceph-pools-audit'
HELM_CHART_HELM_TOOLKIT = 'helm-toolkit'
SUPPORTED_HELM_CHARTS = [
HELM_CHART_AODH,
HELM_CHART_BARBICAN,
HELM_CHART_CEILOMETER,
HELM_CHART_CINDER,
HELM_CHART_GARBD,
HELM_CHART_GLANCE,
HELM_CHART_GNOCCHI,
HELM_CHART_HEAT,
HELM_CHART_HORIZON,
HELM_CHART_INGRESS,
HELM_CHART_IRONIC,
HELM_CHART_KEYSTONE,
HELM_CHART_LIBVIRT,
HELM_CHART_MAGNUM,
HELM_CHART_MARIADB,
HELM_CHART_MEMCACHED,
HELM_CHART_NEUTRON,
HELM_CHART_NOVA,
HELM_CHART_NOVA_API_PROXY,
HELM_CHART_OPENVSWITCH,
HELM_CHART_PANKO,
HELM_CHART_RABBITMQ,
HELM_CHART_RBD_PROVISIONER,
HELM_CHART_CEPH_POOLS_AUDIT,
HELM_CHART_HELM_TOOLKIT,
]
# Helm: Supported application (aka chart bundles)
HELM_APP_OPENSTACK = 'stx-openstack'
@ -1496,34 +1469,6 @@ SUPPORTED_HELM_APP_NAMES = [
HELM_APP_OPENSTACK
]
SUPPORTED_HELM_APP_CHARTS = {
HELM_APP_OPENSTACK: [
HELM_CHART_INGRESS,
HELM_CHART_RBD_PROVISIONER,
HELM_CHART_CEPH_POOLS_AUDIT,
HELM_CHART_MARIADB,
HELM_CHART_GARBD,
HELM_CHART_RABBITMQ,
HELM_CHART_MEMCACHED,
HELM_CHART_KEYSTONE,
HELM_CHART_HEAT,
HELM_CHART_HORIZON,
HELM_CHART_GLANCE,
HELM_CHART_OPENVSWITCH,
HELM_CHART_LIBVIRT,
HELM_CHART_NEUTRON,
HELM_CHART_NOVA,
HELM_CHART_NOVA_API_PROXY,
HELM_CHART_CINDER,
HELM_CHART_GNOCCHI,
HELM_CHART_CEILOMETER,
HELM_CHART_PANKO,
HELM_CHART_AODH,
HELM_CHART_HELM_TOOLKIT,
HELM_CHART_BARBICAN,
]
}
# RBD Provisioner Ceph backend capabilities fields
K8S_RBD_PROV_STORAGECLASS_NAME = 'rbd_storageclass_name' # Customer
K8S_RBD_PROV_NAMESPACES = 'rbd_provisioner_namespaces' # Customer

View File

@ -851,7 +851,7 @@ class AppOperator(object):
def _remove_chart_overrides(self, manifest_file):
charts = self._get_list_of_charts(manifest_file)
for chart in charts:
if chart.name in constants.SUPPORTED_HELM_CHARTS:
if chart.name in self._helm.chart_operators:
self._helm.remove_helm_chart_overrides(chart.name,
chart.namespace)

View File

@ -24,6 +24,12 @@ from sysinv.helm import common
LOG = logging.getLogger(__name__)
# Number of characters to strip off from helm plugin name defined in setup.cfg,
# in order to allow controlling the order of the helm plugins, without changing
# the names of the plugins.
# The convention here is for the helm plugins to be named ###_PLUGINNAME.
HELM_PLUGIN_PREFIX_LENGTH = 4
def helm_context(func):
"""Decorate to initialize the local threading context"""
@ -62,19 +68,31 @@ class HelmOperator(object):
# register chart operators for lookup
self.chart_operators = {}
helm_plugins = extension.ExtensionManager(
namespace='systemconfig.helm_plugins',
invoke_on_load=True, invoke_args=(self,))
# dict containing sequence of helm charts per app
self.helm_applications = self.get_helm_applications()
for plugin in helm_plugins.extensions:
self.chart_operators.update({plugin.name: plugin.obj})
LOG.debug("Loaded helm plugin %s" % plugin.name)
def get_helm_applications(self):
"""Build a dictionary of supported helm applications"""
# build the list of registered supported charts
self.implemented_charts = []
for chart in constants.SUPPORTED_HELM_CHARTS:
if chart in self.chart_operators.keys():
self.implemented_charts.append(chart)
helm_application_dict = {}
helm_applications = extension.ExtensionManager(namespace='systemconfig.helm_applications')
for entry_point in helm_applications.list_entry_points():
helm_application_dict[entry_point.name] = entry_point.module_name
supported_helm_applications = {}
for name, namespace in helm_application_dict.items():
supported_helm_applications[name] = []
helm_plugins = extension.ExtensionManager(namespace=namespace, invoke_on_load=True, invoke_args=(self,))
sorted_helm_plugins = sorted(helm_plugins.extensions, key=lambda x: x.name)
for plugin in sorted_helm_plugins:
plugin_name = plugin.name[HELM_PLUGIN_PREFIX_LENGTH:]
self.chart_operators.update({plugin_name: plugin.obj})
# Remove duplicates, keeping last occurrence only
if plugin_name in supported_helm_applications[name]:
supported_helm_applications[name].remove(plugin_name)
supported_helm_applications[name].append(plugin_name)
return supported_helm_applications
@property
def context(self):
@ -92,7 +110,7 @@ class HelmOperator(object):
"""
namespaces = []
if chart_name in self.implemented_charts:
if chart_name in self.chart_operators:
namespaces = self.chart_operators[chart_name].get_namespaces()
return namespaces
@ -136,9 +154,8 @@ class HelmOperator(object):
}
}
"""
overrides = {}
if chart_name in self.implemented_charts:
if chart_name in self.chart_operators:
try:
overrides.update(
self.chart_operators[chart_name].get_overrides(
@ -160,15 +177,14 @@ class HelmOperator(object):
"""
app_namespaces = {}
if app_name in constants.SUPPORTED_HELM_APP_NAMES:
for chart_name in constants.SUPPORTED_HELM_APP_CHARTS[app_name]:
if chart_name in self.implemented_charts:
try:
app_namespaces.update({chart_name:
self.get_helm_chart_namespaces(
chart_name)})
except exception.InvalidHelmNamespace as e:
LOG.info(e)
if app_name in self.helm_applications:
for chart_name in self.helm_applications[app_name]:
try:
app_namespaces.update({chart_name:
self.get_helm_chart_namespaces(
chart_name)})
except exception.InvalidHelmNamespace as e:
LOG.info(e)
return app_namespaces
@helm_context
@ -217,18 +233,16 @@ class HelmOperator(object):
}
}
"""
overrides = {}
if app_name in constants.SUPPORTED_HELM_APP_NAMES:
for chart_name in constants.SUPPORTED_HELM_APP_CHARTS[app_name]:
if chart_name in self.implemented_charts:
try:
overrides.update({chart_name:
self._get_helm_chart_overrides(
chart_name,
cnamespace)})
except exception.InvalidHelmNamespace as e:
LOG.info(e)
if app_name in self.helm_applications:
for chart_name in self.helm_applications[app_name]:
try:
overrides.update({chart_name:
self._get_helm_chart_overrides(
chart_name,
cnamespace)})
except exception.InvalidHelmNamespace as e:
LOG.info(e)
return overrides
def _get_helm_chart_location(self, chart_name):
@ -239,7 +253,7 @@ class HelmOperator(object):
:param chart_name: name of the chart
:returns: a URL as location or None if the chart is not supported
"""
if chart_name in self.implemented_charts:
if chart_name in self.chart_operators:
return self.chart_operators[chart_name].get_chart_location(
chart_name)
return None
@ -342,7 +356,7 @@ class HelmOperator(object):
:param cnamespace: (optional) namespace
"""
if chart_name in self.implemented_charts:
if chart_name in self.chart_operators:
namespaces = self.chart_operators[chart_name].get_namespaces()
if cnamespace and cnamespace not in namespaces:
LOG.exception("The %s chart does not support namespace: %s" %
@ -367,7 +381,7 @@ class HelmOperator(object):
@helm_context
def generate_meta_overrides(self, chart_name, chart_namespace):
overrides = {}
if chart_name in self.implemented_charts:
if chart_name in self.chart_operators:
try:
overrides.update(
self.chart_operators[chart_name].get_meta_overrides(
@ -396,7 +410,7 @@ class HelmOperator(object):
system overrides
"""
if app_name in constants.SUPPORTED_HELM_APP_NAMES:
if app_name in self.helm_applications:
app_overrides = self._get_helm_application_overrides(app_name,
cnamespace)
for (chart_name, overrides) in iteritems(app_overrides):
@ -438,7 +452,6 @@ class HelmOperator(object):
new_overrides = self._add_armada_override_header(
chart_name, key, overrides[key])
overrides[key] = new_overrides
self._write_chart_overrides(chart_name, cnamespace, overrides)
# Write any meta-overrides for this chart. These will be in
@ -459,7 +472,7 @@ class HelmOperator(object):
def remove_helm_chart_overrides(self, chart_name, cnamespace=None):
"""Remove the overrides files for a chart"""
if chart_name in self.implemented_charts:
if chart_name in self.chart_operators:
namespaces = self.chart_operators[chart_name].get_namespaces()
filenames = []