Merge "App Fmwk: Add support for FluxCDKustomizeOperator"

This commit is contained in:
Zuul 2022-05-24 21:32:57 +00:00 committed by Gerrit Code Review
commit bdd96b4ce5
13 changed files with 800 additions and 141 deletions

View File

@ -74,6 +74,9 @@ systemconfig.puppet_plugins =
systemconfig.armada.manifest_ops =
generic = sysinv.helm.manifest_generic:GenericArmadaManifestOperator
systemconfig.fluxcd.kustomize_ops =
generic = sysinv.helm.kustomize_generic:GenericFluxCDKustomizeOperator
systemconfig.app_lifecycle =
generic = sysinv.helm.lifecycle_generic:GenericAppLifecycleOperator

View File

@ -167,7 +167,7 @@ class KubeAppController(rest.RestController):
try:
name, version, patches = app_helper._verify_metadata_file(
app_path, app_name, app_version)
mname, manifest = app_helper._find_manifest(app_path)
mname, manifest = app_helper._find_manifest(app_path, name)
app_helper._extract_helm_charts(app_path)
LOG.info("Tar file of application %s verified." % name)
return name, version, mname, manifest
@ -669,31 +669,51 @@ class KubeAppHelper(object):
raise exception.IncompatibleKubeVersion(
name=app_name, version=app_version, kube_version=kube_version)
def _find_manifest(self, app_path):
mdir = cutils.find_manifest_directory(app_path)
def _find_manifest(self, app_path, app_name):
""" Find the required application manifest elements
if mdir:
return mdir
Check for an Armada manifest or a FluxCD manifest directory
"""
try:
# Check for the presence of a FluxCD manifest directory
mfile = self._find_fluxcd_manifest(app_path, app_name)
except exception.SysinvException as fluxcd_e:
try:
# Check for the presence of an Armada manifest
mfile = self._find_armada_manifest(app_path)
except exception.SysinvException as armada_e:
raise exception.SysinvException(_(
"Application-upload rejected: {} and {} ".format(
fluxcd_e, armada_e)))
return mfile
def _find_fluxcd_manifest(self, app_path, app_name):
mfiles = cutils.find_fluxcd_manifests_directory(app_path, app_name)
if mfiles:
return mfiles[0]
raise exception.SysinvException(_(
"FluxCD manifest structure is not present"))
def _find_armada_manifest(self, app_path):
# It is expected that there is only one manifest file
# per application and the file exists at top level of
# the application path.
mfiles = cutils.find_manifest_file(app_path)
mfiles = cutils.find_armada_manifest_file(app_path)
if mfiles is None:
raise exception.SysinvException(_(
"manifest file is corrupted."))
"Armada manifest file is corrupted."))
if mfiles:
if len(mfiles) == 1:
return mfiles[0]
else:
raise exception.SysinvException(_(
"Application-upload rejected: tar file contains more "
"than one manifest file."))
"tar file contains more than one Armada manifest file."))
raise exception.SysinvException(_(
"Application-upload rejected: manifest file/directory is missing."))
"Armada manifest file/directory is missing"))
def _verify_metadata_file(self, app_path, app_name, app_version,
upgrade_from_release=None):

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (c) 2021 Wind River Systems, Inc.
# Copyright (c) 2021-2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -10,6 +10,7 @@ System Inventory Helm Utility.
"""
import sys
import urllib3
from oslo_config import cfg
from oslo_log import log
@ -26,13 +27,13 @@ CONF = cfg.CONF
LOG = log.getLogger(__name__)
def create_app_overrides_action(path, app_name=None, namespace=None):
def create_fluxcd_app_overrides_action(path, app_name=None, namespace=None):
dbapi = api.get_instance()
try:
db_app = dbapi.kube_app_get(app_name)
except exception.KubeAppNotFound:
LOG.info("Application %s not found" % app_name)
LOG.info("FluxCD Application %s not found" % app_name)
return
helm_operator = helm.HelmOperator(dbapi=dbapi)
@ -45,11 +46,14 @@ def create_app_overrides_action(path, app_name=None, namespace=None):
if db_app.status == constants.APP_UPLOAD_SUCCESS:
app_operator.activate_app_plugins(db_app)
helm_operator.generate_helm_application_overrides(
path, app_name, mode=None, cnamespace=namespace)
path, app_name, mode=None, cnamespace=namespace,
armada_format=False, chart_info=None, combined=False,
is_fluxcd_app=True)
app_operator.deactivate_app_plugins(db_app)
else:
helm_operator.generate_helm_application_overrides(
path, app_name, mode=None, cnamespace=namespace)
path, app_name, mode=None, cnamespace=namespace,
is_fluxcd_app=True)
def create_armada_app_overrides_action(path, app_name=None, namespace=None):
@ -72,17 +76,18 @@ def create_armada_app_overrides_action(path, app_name=None, namespace=None):
app_operator.activate_app_plugins(db_app)
helm_operator.generate_helm_application_overrides(
path, app_name, mode=None, cnamespace=namespace,
armada_format=True, armada_chart_info=None, combined=False)
armada_format=False, chart_info=None, combined=False,
is_fluxcd_app=False)
app_operator.deactivate_app_plugins(db_app)
else:
helm_operator.generate_helm_application_overrides(
path, app_name, mode=None, cnamespace=namespace,
armada_format=True, armada_chart_info=None, combined=False)
is_fluxcd_app=False)
def add_action_parsers(subparsers):
parser = subparsers.add_parser('create-app-overrides')
parser.set_defaults(func=create_app_overrides_action)
parser = subparsers.add_parser('create-fluxcd-app-overrides')
parser.set_defaults(func=create_fluxcd_app_overrides_action)
parser.add_argument('path', nargs='?')
parser.add_argument('app_name', nargs='?')
parser.add_argument('namespace', nargs='?')
@ -102,21 +107,23 @@ CONF.register_cli_opt(
def main():
urllib3.disable_warnings()
service.prepare_service(sys.argv)
if CONF.action.name == 'create-app-overrides':
if CONF.action.name == 'create-fluxcd-app-overrides':
if not CONF.action.path:
LOG.error("overrides path is required")
LOG.error("A path is required to save overrides")
elif not CONF.action.app_name:
LOG.error("application name is required")
LOG.error("FluxCD application name is required")
else:
CONF.action.func(CONF.action.path,
CONF.action.app_name,
CONF.action.namespace)
elif CONF.action.name == 'create-armada-app-overrides':
if not CONF.action.path:
LOG.error("overrides path is required")
LOG.error("A path is required to save overrides")
elif not CONF.action.app_name:
LOG.error("application name is required")
LOG.error("Armada application name is required")
else:
CONF.action.func(CONF.action.path,
CONF.action.app_name,

View File

@ -1650,12 +1650,21 @@ K8S_RBD_PROV_STOR_CLASS_NAME = 'general'
# Working paths
APP_INSTALL_ROOT_PATH = '/scratch'
APP_INSTALL_PATH = APP_INSTALL_ROOT_PATH + '/apps'
APP_SYNCED_ARMADA_DATA_PATH = os.path.join(tsc.PLATFORM_PATH, 'armada', tsc.SW_VERSION)
APP_METADATA_FILE = 'metadata.yaml'
APP_PENDING_REAPPLY_FLAG = os.path.join(
tsc.HELM_OVERRIDES_PATH, ".app_reapply")
# Armada
APP_SYNCED_ARMADA_DATA_PATH = os.path.join(tsc.PLATFORM_PATH, 'armada', tsc.SW_VERSION)
# FluxCD
APP_FLUXCD_MANIFEST_DIR = 'fluxcd-manifests'
APP_FLUXCD_DATA_PATH = os.path.join(tsc.PLATFORM_PATH, 'fluxcd', tsc.SW_VERSION)
APP_ROOT_KUSTOMIZE_FILE = 'kustomization.yaml'
APP_RELEASE_CLEANUP_FILE = 'helmrelease_cleanup.yaml'
FLUXCD_CRD_HELM_REL_GROUP = 'helm.toolkit.fluxcd.io'
FLUXCD_CRD_HELM_REL_VERSION = 'v2beta1'
FLUXCD_CRD_HELM_REL_PLURAL = 'helmreleases'
# State constants
APP_NOT_PRESENT = 'missing'

View File

@ -634,7 +634,7 @@ class KubeOperator(object):
custom_resource_api = self._get_kubernetesclient_custom_objects()
try:
cert = custom_resource_api.get_namespaced_custom_object(
cr_obj = custom_resource_api.get_namespaced_custom_object(
group,
version,
namespace,
@ -647,14 +647,14 @@ class KubeOperator(object):
LOG.error("Fail to access %s:%s. %s" % (namespace, name, e))
raise
else:
return cert
return cr_obj
def apply_custom_resource(self, group, version, namespace, plural, name, body):
custom_resource_api = self._get_kubernetesclient_custom_objects()
# if resource already exists we apply just a patch
cert = self.get_custom_resource(group, version, namespace, plural, name)
if cert:
cr_obj = self.get_custom_resource(group, version, namespace, plural, name)
if cr_obj:
custom_resource_api.patch_namespaced_custom_object(group,
version,
namespace,
@ -677,11 +677,12 @@ class KubeOperator(object):
plural, name, body)
except ApiException as ex:
if ex.reason == "Not Found":
LOG.warn("Failed to delete custom object, Namespace %s: %s"
% (namespace, str(ex.body).replace('\n', ' ')))
LOG.warn("Failed to delete custom resource object, Namespace "
"%s: %s" % (namespace,
str(ex.body).replace('\n', ' ')))
pass
except Exception as e:
LOG.error("Failed to delete custom object, Namespace %s: %s"
LOG.error("Failed to delete custom resource object, Namespace %s: %s"
% (namespace, e))
raise

View File

@ -2453,9 +2453,9 @@ def find_metadata_file(path, metadata_file, upgrade_from_release=None):
return app_name, app_version, patches
def find_manifest_file(path):
""" Find all manifest files in a given directory. """
def _is_manifest(yaml_file):
def find_armada_manifest_file(path):
""" Find all Armada manifest files in a given directory. """
def _is_armada_manifest(yaml_file):
with io.open(yaml_file, 'r', encoding='utf-8') as f:
docs = yaml.load_all(f)
for doc in docs:
@ -2473,7 +2473,7 @@ def find_manifest_file(path):
if file.endswith('.yaml'):
yaml_file = os.path.join(path, file)
try:
mname, mfile = _is_manifest(yaml_file)
mname, mfile = _is_armada_manifest(yaml_file)
if mfile:
mfiles.append((mname, mfile))
except Exception as e:
@ -2484,21 +2484,25 @@ def find_manifest_file(path):
return mfiles
def find_manifest_directory(path):
"""For FluxCD apps we expect to have 1 manifest directory
that has the name of constants.APP_FLUXCD_MANIFEST_DIR
and we validate that and its structure"""
def _is_manifest_dir(path):
"""check if the directory has the desired FluxCD app structure"""
mandatory_components = ("base", "kustomization.yaml")
def find_fluxcd_manifests_directory(path, name):
"""For FluxCD apps we expect to have one top-level manifest directory that
contains the name of constants.APP_FLUXCD_MANIFEST_DIR. Validate that it
is present and provide some basic validation of its structure.
"""
def _is_fluxcd_app_compliant(path):
"""Check if the directory has the desired FluxCD app structure"""
mandatory_components = ("base", constants.APP_ROOT_KUSTOMIZE_FILE)
check_mandatory = all(comp in os.listdir(path)
for comp in mandatory_components)
return check_mandatory
mfiles = []
manifest_dir_abs = os.path.join(path, constants.APP_FLUXCD_MANIFEST_DIR)
if os.path.isdir(manifest_dir_abs) and _is_manifest_dir(manifest_dir_abs):
return constants.APP_FLUXCD_MANIFEST_DIR, manifest_dir_abs
return None
if os.path.isdir(manifest_dir_abs) and \
_is_fluxcd_app_compliant(manifest_dir_abs):
mfiles.append((("{}-{}".format(name, constants.APP_FLUXCD_MANIFEST_DIR)),
manifest_dir_abs))
return mfiles
def get_http_port(dbapi):
@ -2638,32 +2642,38 @@ def is_aio_duplex_system(dbapi):
def generate_synced_armada_dir(app_name, app_version):
""" Armada application: Top level directory. """
return os.path.join(constants.APP_SYNCED_ARMADA_DATA_PATH, app_name, app_version)
def generate_synced_armada_manifest_fqpn(app_name, app_version, manifest_filename):
""" Armada application: Armada manifest file. """
return os.path.join(
constants.APP_SYNCED_ARMADA_DATA_PATH, app_name, app_version,
app_name + '-' + manifest_filename)
def generate_synced_metadata_fqpn(app_name, app_version):
""" Armada application: Application metadata file. """
return os.path.join(
constants.APP_SYNCED_ARMADA_DATA_PATH, app_name, app_version,
'metadata.yaml')
def generate_synced_fluxcd_dir(app_name, app_version):
""" FluxCD application: Top level directory. """
return os.path.join(constants.APP_FLUXCD_DATA_PATH, app_name, app_version)
def generate_synced_fluxcd_manifest_fqpn(app_name, app_version, manifest):
def generate_synced_fluxcd_manifests_fqpn(app_name, app_version):
""" FluxCD application: Top level kustomize manifests directory. """
return os.path.join(
constants.APP_FLUXCD_DATA_PATH, app_name, app_version,
app_name + '-' + manifest)
app_name + '-' + constants.APP_FLUXCD_MANIFEST_DIR)
def generate_synced_fluxcd_metadata_fqpn(app_name, app_version):
""" FluxCD application: Application metadata file. """
return os.path.join(
constants.APP_FLUXCD_DATA_PATH, app_name, app_version,
'metadata.yaml')

View File

@ -519,7 +519,7 @@ class AppOperator(object):
if not cutils.verify_checksum(app.inst_path):
_handle_extract_failure('checksum validation failed.')
mname, manifest = self._utils._find_manifest(app.inst_path)
mname, manifest = self._utils._find_manifest(app.inst_path, app.name)
# Save the official manifest file info. They will be persisted
# in the next status update
app.regenerate_manifest_filename(mname, os.path.basename(manifest))
@ -567,7 +567,8 @@ class AppOperator(object):
images_file = yaml.safe_load(f)
helmrepo_path = os.path.join(manifest, "base", "helmrepository.yaml")
root_kustomization_path = os.path.join(manifest, "kustomization.yaml")
root_kustomization_path = os.path.join(
manifest, constants.APP_ROOT_KUSTOMIZE_FILE)
for f in (helmrepo_path, root_kustomization_path):
if not os.path.isfile(f):
raise exception.SysinvException(_(
@ -629,7 +630,7 @@ class AppOperator(object):
not os.path.isfile(static_overrides_path):
raise exception.SysinvException(_(
"FluxCD app chart static overrides file doesn't exist "
"%s" % static_overrides_path))
"%s" % chart_name))
with io.open(static_overrides_path, 'r', encoding='utf-8') as f:
static_overrides_file = yaml.safe_load(f) or {}
@ -791,7 +792,7 @@ class AppOperator(object):
LOG.info("Generating application overrides to discover required images.")
self._helm.generate_helm_application_overrides(
app.sync_overrides_dir, app.name, mode=None, cnamespace=None,
armada_format=True, armada_chart_info=app.charts, combined=True,
armada_format=True, chart_info=app.charts, combined=True,
is_fluxcd_app=app.is_fluxcd_app)
self._plugins.deactivate_plugins(app)
@ -1235,7 +1236,8 @@ class AppOperator(object):
"""
helmrepo_path = os.path.join(manifest, "base", "helmrepository.yaml")
root_kustomization_path = os.path.join(manifest, "kustomization.yaml")
root_kustomization_path = os.path.join(
manifest, constants.APP_ROOT_KUSTOMIZE_FILE)
for f in (helmrepo_path, root_kustomization_path):
if not os.path.isfile(f):
raise exception.SysinvException(_(
@ -1659,9 +1661,12 @@ class AppOperator(object):
constants.APP_METADATA_APPLY_PROGRESS_ADJUST,
constants.APP_METADATA_APPLY_PROGRESS_ADJUST_DEFAULT_VALUE)
# Build the list of expected chart releases. Re-read the
# kustomization.yaml file as charts may have been enabled/disabled
# via the plugins (helm or kustomize operator).
charts = {
c.metadata_name: {"namespace": c.namespace, "chart_label": c.chart_label}
for c in app.charts
for c in self._get_list_of_charts(app)
}
charts_count = len(charts)
@ -1691,8 +1696,10 @@ class AppOperator(object):
for release_name, chart_obj in list(charts.items()):
# Request the helm release info
helm_rel = self._kube.get_custom_resource(
"helm.toolkit.fluxcd.io", "v2beta1",
chart_obj["namespace"], "helmreleases",
constants.FLUXCD_CRD_HELM_REL_GROUP,
constants.FLUXCD_CRD_HELM_REL_VERSION,
chart_obj["namespace"],
constants.FLUXCD_CRD_HELM_REL_PLURAL,
release_name)
if not helm_rel:
@ -2744,7 +2751,7 @@ class AppOperator(object):
LOG.info("Generating application overrides...")
self._helm.generate_helm_application_overrides(
app.sync_overrides_dir, app.name, mode, cnamespace=None,
armada_format=True, armada_chart_info=app.charts, combined=True,
armada_format=True, chart_info=app.charts, combined=True,
is_fluxcd_app=app.is_fluxcd_app)
overrides_str = None
@ -3281,51 +3288,53 @@ class AppOperator(object):
self.sync_armada_mfile_dir = cutils.generate_synced_armada_dir(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_fluxcd_manifest_dir = cutils.generate_synced_fluxcd_dir(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
# Files: DRBD synced between controllers
self.sync_armada_mfile = cutils.generate_synced_armada_manifest_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'),
self._kube_app.get('manifest_file'))
self.sync_imgfile = generate_synced_images_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_metadata_file = cutils.generate_synced_metadata_fqpn(
self.sync_fluxcd_manifest = cutils.generate_synced_fluxcd_manifests_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
# Files: FQPN formatted for the docker armada_service
self.sync_armada_imgfile = generate_synced_images_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_fluxcd_imgfile = generate_synced_fluxcd_images_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_imgfile = self.sync_fluxcd_imgfile \
if self.is_fluxcd_app else \
self.sync_armada_imgfile
self.sync_armada_metadata_file = cutils.generate_synced_metadata_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_fluxcd_metadata_file = cutils.generate_synced_fluxcd_metadata_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_metadata_file = self.sync_fluxcd_metadata_file \
if self.is_fluxcd_app else \
self.sync_armada_metadata_file
# Files: FQPN formatted for the Armada pod
self.armada_service_mfile = generate_armada_service_manifest_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'),
self._kube_app.get('manifest_file'))
# FluxCD variables
if self.is_fluxcd_app:
self.sync_fluxcd_manifest_dir = cutils.generate_synced_fluxcd_dir(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_fluxcd_manifest = cutils.generate_synced_fluxcd_manifest_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'),
self._kube_app.get('manifest_file'))
# override the common variables
self.sync_metadata_file = cutils.generate_synced_fluxcd_metadata_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.sync_imgfile = generate_synced_fluxcd_images_fqpn(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.patch_dependencies = []
self.charts = []
self.releases = []
@property
def is_fluxcd_app(self):
return self._kube_app.get('manifest_name') \
== constants.APP_FLUXCD_MANIFEST_DIR
return self._kube_app.get('manifest_name').endswith(
constants.APP_FLUXCD_MANIFEST_DIR)
@property
def system_app(self):
@ -3390,10 +3399,9 @@ class AppOperator(object):
self.inst_mfile = generate_install_manifest_fqpn(
self.name, self.version, new_mfile)
if self.is_fluxcd_app:
self.sync_fluxcd_manifest = cutils.generate_synced_fluxcd_manifest_fqpn(
self.sync_fluxcd_manifest = cutils.generate_synced_fluxcd_manifests_fqpn(
self.name,
self.version,
new_mfile)
self.version)
else:
self.armada_service_mfile = generate_armada_service_manifest_fqpn(
self.name, self.version, new_mfile)
@ -4448,6 +4456,11 @@ class FluxCDHelper(object):
try:
if operation == constants.APP_APPLY_OP:
rc = self._apply(manifest_dir)
if rc:
rc = self._cleanup_disabled_helm_releases(manifest_dir)
else:
LOG.error("Applying %s failed. Skipping helm release "
"cleanup...")
elif operation == constants.APP_DELETE_OP:
rc = self._delete(manifest_dir)
elif operation == constants.APP_ROLLBACK_OP:
@ -4559,3 +4572,38 @@ class FluxCDHelper(object):
return conditions[0]['status'], conditions[0].get('message')
else:
return self.HELM_RELEASE_STATUS_UNKNOWN, None
def _cleanup_disabled_helm_releases(self, manifest_dir):
helmrelease_cleanup_fqpn = os.path.join(
manifest_dir, constants.APP_RELEASE_CLEANUP_FILE)
# See if we have any helm releases that we must make sure are cleaned up
if not os.path.exists(helmrelease_cleanup_fqpn):
return True
with io.open(helmrelease_cleanup_fqpn, 'r', encoding='utf-8') as f:
helmrelease_doc = list(yaml.load_all(f,
Loader=yaml.RoundTripLoader, preserve_quotes=True))
for release in helmrelease_doc[0]['releases']:
try:
if self._kube.get_custom_resource(
constants.FLUXCD_CRD_HELM_REL_GROUP,
constants.FLUXCD_CRD_HELM_REL_VERSION,
release["namespace"],
constants.FLUXCD_CRD_HELM_REL_PLURAL,
release['name']):
self._kube.delete_custom_resource(
constants.FLUXCD_CRD_HELM_REL_GROUP,
constants.FLUXCD_CRD_HELM_REL_VERSION,
release["namespace"],
constants.FLUXCD_CRD_HELM_REL_PLURAL,
release['name'])
except Exception as e:
LOG.error("Attemting to cleanup HelmRelease {}/{} "
"failed".format(release["namespace"],
release['name']))
LOG.exception(e)
return False
return True

View File

@ -6409,7 +6409,7 @@ class ConductorManager(service.PeriodicService):
self._kube_app_helper._verify_metadata_file(
app_path, app_name, None)
manifest_name, manifest_file = \
self._kube_app_helper._find_manifest(app_path)
self._kube_app_helper._find_manifest(app_path, app_name)
self._kube_app_helper._extract_helm_charts(app_path)
except exception.SysinvException as e:
LOG.error("Extracting tarfile for %s failed: %s." % (
@ -13784,7 +13784,7 @@ class ConductorManager(service.PeriodicService):
app.charts = self._app._get_list_of_charts(app)
self._helm.generate_helm_application_overrides(
app.sync_overrides_dir, app.name, app.mode, cnamespace=None,
armada_format=True, armada_chart_info=app.charts, combined=True,
armada_format=True, chart_info=app.charts, combined=True,
is_fluxcd_app=app.is_fluxcd_app)
(helm_files, armada_files) = self._app._get_overrides_files(app, None)
for f in helm_files + armada_files:

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
# Copyright (c) 2018-2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -418,6 +418,21 @@ class BaseHelm(object):
"""
pass
def execute_kustomize_updates(self, operator):
"""
Update the elements of FluxCD kustomize manifests.
This allows a helm chart plugin to use the FluxCDKustomizeOperator to
make dynamic structural changes to the application manifest based on the
current conditions in the platform
Changes currenty include updates to the top level kustomize manifest to
disable helm releases.
:param operator: an instance of the FluxCDKustomizeOperator
"""
pass
def _is_enabled(self, app_name, chart_name, namespace):
"""
Check if the chart is enable at an application level

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2018-2021 Wind River Systems, Inc.
# Copyright (c) 2018-2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -42,6 +42,12 @@ HELM_PLUGIN_PREFIX_LENGTH = 4
# optional suffix, as in PLUGINNAME_###.
ARMADA_PLUGIN_SUFFIX_LENGTH = 4
# Number of optional characters appended to FluxCD kustomize operator name, to
# allow overriding with a newer version of the FluxCD kustomize operator. The
# convention here is for the FluxCD kustomize operator plugins to allow an
# optional suffix, as in PLUGINNAME_###.
FLUXCD_PLUGIN_SUFFIX_LENGTH = 4
# Number of optional characters appended to AppLifecycle operator name,
# to allow overriding with a newer version of the AppLifecycle operator.
# The convention here is for the AppLifecycle operator plugins to allow an
@ -78,6 +84,7 @@ class HelmOperator(object):
# Define the stevedore namespaces that will need to be managed for plugins
STEVEDORE_APPS = 'systemconfig.helm_applications'
STEVEDORE_ARMADA = 'systemconfig.armada.manifest_ops'
STEVEDORE_FLUXCD = 'systemconfig.fluxcd.kustomize_ops'
STEVEDORE_LIFECYCLE = 'systemconfig.app_lifecycle'
def __init__(self, dbapi=None):
@ -97,6 +104,7 @@ class HelmOperator(object):
self.helm_system_applications = {}
self.chart_operators = {}
self.armada_manifest_operators = {}
self.fluxcd_kustomize_operators = {}
self.app_lifecycle_operators = {}
# Need to purge the stevedore plugin cache so that when we discover the
@ -110,6 +118,9 @@ class HelmOperator(object):
# dict containing Armada manifest operators per app
self.armada_manifest_operators = self._load_armada_manifest_operators()
# dict containing FluxCD kustomize operators per app
self.fluxcd_kustomize_operators = self._load_fluxcd_kustomize_operators()
# dict containing app lifecycle operators per app
self.app_lifecycle_operators = self._load_app_lifecycle_operators()
@ -168,6 +179,32 @@ class HelmOperator(object):
LOG.info("Couldn't find endpoint distribution located at %s for "
"%s" % (install_location, armada_distribution))
for fluxcd_ep in extension.ExtensionManager.ENTRY_POINT_CACHE[self.STEVEDORE_FLUXCD]:
fluxcd_distribution = None
try:
fluxcd_distribution = utils.get_distribution_from_entry_point(fluxcd_ep)
(project_name, project_location) = \
utils.get_project_name_and_location_from_distribution(fluxcd_distribution)
if project_location == install_location:
extension.ExtensionManager.ENTRY_POINT_CACHE[self.STEVEDORE_FLUXCD].remove(fluxcd_ep)
break
except exception.SysinvException:
# Temporary suppress errors on Debian until Stevedore is reworked.
# See https://storyboard.openstack.org/#!/story/2009101
if utils.is_debian():
LOG.info("Didn't find distribution for {}. Deleting from cache".format(fluxcd_ep))
try:
extension.ExtensionManager.ENTRY_POINT_CACHE[self.STEVEDORE_FLUXCD].remove(fluxcd_ep)
except Exception as e:
LOG.info("Tried removing fluxcd_ep {}, error: {}".format(fluxcd_ep, e))
else:
raise
else:
LOG.info("Couldn't find endpoint distribution located at %s for "
"%s" % (install_location, fluxcd_distribution))
for app_ep in extension.ExtensionManager.ENTRY_POINT_CACHE[self.STEVEDORE_APPS]:
try:
app_distribution = utils.get_distribution_from_entry_point(app_ep)
@ -227,6 +264,12 @@ class HelmOperator(object):
except KeyError:
LOG.info("No entry points for %s found." % self.STEVEDORE_ARMADA)
try:
del extension.ExtensionManager.ENTRY_POINT_CACHE[self.STEVEDORE_FLUXCD]
LOG.debug("Deleted entry points for %s." % self.STEVEDORE_FLUXCD)
except KeyError:
LOG.info("No entry points for %s found." % self.STEVEDORE_FLUXCD)
try:
del extension.ExtensionManager.ENTRY_POINT_CACHE[self.STEVEDORE_LIFECYCLE]
LOG.debug("Deleted entry points for %s." % self.STEVEDORE_LIFECYCLE)
@ -304,6 +347,44 @@ class HelmOperator(object):
return operators_dict
def _load_fluxcd_kustomize_operators(self):
"""Build a dictionary of FluxCD kustomize operators"""
operators_dict = {}
dist_info_dict = {}
fluxcd_kustomize_operators = extension.ExtensionManager(
namespace=self.STEVEDORE_FLUXCD,
invoke_on_load=True, invoke_args=())
sorted_fluxcd_kustomize_operators = sorted(
fluxcd_kustomize_operators.extensions, key=lambda x: x.name)
for op in sorted_fluxcd_kustomize_operators:
if (op.name[-(FLUXCD_PLUGIN_SUFFIX_LENGTH - 1):].isdigit() and
op.name[-FLUXCD_PLUGIN_SUFFIX_LENGTH:-3] == '_'):
op_name = op.name[0:-FLUXCD_PLUGIN_SUFFIX_LENGTH]
else:
op_name = op.name
operators_dict[op_name] = op.obj
distribution = utils.get_distribution_from_entry_point(op.entry_point)
(project_name, project_location) = \
utils.get_project_name_and_location_from_distribution(distribution)
# Extract distribution information for logging
dist_info_dict[op_name] = {
'name': project_name,
'location': project_location,
}
# Provide some log feedback on plugins being used
for (app_name, info) in iteritems(dist_info_dict):
LOG.info("Plugins for %-20s: loaded from %-20s - %s." % (app_name,
info['name'], info['location']))
return operators_dict
def get_armada_manifest_operator(self, app_name):
"""Return a manifest operator based on app name"""
@ -314,6 +395,16 @@ class HelmOperator(object):
manifest_op = self.armada_manifest_operators['generic']
return manifest_op
def get_fluxcd_kustomize_operator(self, app_name):
"""Return a kustomize operator based on app name"""
plugin_name = utils.find_app_plugin_name(app_name)
if plugin_name in self.fluxcd_kustomize_operators:
kustomize_op = self.fluxcd_kustomize_operators[plugin_name]
else:
kustomize_op = self.fluxcd_kustomize_operators['generic']
return kustomize_op
def _load_helm_applications(self):
"""Build a dictionary of supported helm applications"""
@ -725,7 +816,7 @@ class HelmOperator(object):
mode=None,
cnamespace=None,
armada_format=False,
armada_chart_info=None,
chart_info=None,
combined=False,
is_fluxcd_app=False):
"""Create the system overrides files for a supported application
@ -741,28 +832,59 @@ class HelmOperator(object):
:param cnamespace: (optional) namespace
:param armada_format: (optional) whether to emit in armada format
instead of helm format (with extra header)
:param armada_chart_info: (optional) supporting chart information
:param chart_info: (optional) supporting chart information
extracted from the armada manifest which is used to influence
overrides
:param combined: (optional) whether to apply user overrides on top of
system overrides
:param is_fluxcd_app: whether the app is fluxcd or not
"""
if is_fluxcd_app:
self._generate_helm_application_overrides_fluxcd(
path, app_name, mode, cnamespace,
chart_info, combined)
else:
self._generate_helm_application_overrides_armada(
path, app_name, mode, cnamespace, armada_format,
chart_info, combined)
@helm_context
def _generate_helm_application_overrides_armada(self, path, app_name,
mode=None,
cnamespace=None,
armada_format=False,
chart_info=None,
combined=False):
"""Create the system overrides files for a supported application
This method will generate system helm chart overrides yaml files for a
set of supported charts that comprise an application. If the namespace
is provided only the overrides files for that specified namespace will
be written.
:param app_name: name of the bundle of charts required to support an
application
:param mode: mode to control how to apply application manifest
:param cnamespace: (optional) namespace
:param armada_format: (optional) whether to emit in armada format
instead of helm format (with extra header)
:param chart_info: (optional) supporting chart information
extracted from the armada manifest which is used to influence
overrides
:param combined: (optional) whether to apply user overrides on top of
system overrides
"""
app, plugin_name = self._find_kube_app_and_app_plugin_name(app_name)
if is_fluxcd_app:
armada_format = False
# 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)
else:
# 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_synced_armada_manifest_fqpn(
app.name, app.app_version, app.manifest_file)
manifest_op.load(armada_manifest)
# Load the manifest into the operator
armada_manifest = utils.generate_synced_armada_manifest_fqpn(
app.name, app.app_version, app.manifest_file)
manifest_op.load(armada_manifest)
if plugin_name in self.helm_system_applications:
app_overrides = self._get_helm_application_overrides(plugin_name,
@ -802,34 +924,31 @@ class HelmOperator(object):
# If armada formatting is wanted, we need to change the
# structure of the yaml file somewhat
if armada_format:
for key in overrides:
metadata_name, repo_name, chart_tarfile = \
self._get_chart_info_from_armada_chart(chart_name, key,
armada_chart_info)
new_overrides = self._add_armada_override_header(
chart_name, metadata_name, repo_name, chart_tarfile,
key, overrides[key])
overrides[key] = new_overrides
for key in overrides:
metadata_name, repo_name, chart_tarfile = \
self._get_chart_info_from_armada_chart(chart_name, key,
chart_info)
new_overrides = self._add_armada_override_header(
chart_name, metadata_name, repo_name, chart_tarfile,
key, overrides[key])
overrides[key] = new_overrides
self._write_chart_overrides(path, chart_name, cnamespace, overrides)
if not is_fluxcd_app:
# Update manifest docs based on the plugin directives. If the
# application does not provide a manifest operator, the
# GenericArmadaManifestOperator is used and chart specific
# operations can be skipped.
if manifest_op.APP:
if chart_name in self.chart_operators:
self.chart_operators[chart_name].execute_manifest_updates(
manifest_op)
# Update manifest docs based on the plugin directives. If the
# application does not provide a manifest operator, the
# GenericArmadaManifestOperator is used and chart specific
# operations can be skipped.
if manifest_op.APP:
if chart_name in self.chart_operators:
self.chart_operators[chart_name].execute_manifest_updates(
manifest_op)
if not is_fluxcd_app:
# Update the manifest based on platform conditions
manifest_op.platform_mode_manifest_updates(self.dbapi, mode)
# Update the manifest based on platform conditions
manifest_op.platform_mode_manifest_updates(self.dbapi, mode)
else:
# Generic applications
for chart in armada_chart_info:
for chart in chart_info:
try:
db_chart = self.dbapi.helm_override_get(
app.id, chart.name, chart.namespace)
@ -855,24 +974,142 @@ class HelmOperator(object):
user_overrides = yaml.load(yaml.dump(
{chart.namespace: yaml.load(db_user_overrides)}))
if armada_format:
metadata_name, repo_name, chart_tarfile =\
self._get_chart_info_from_armada_chart(chart.name, chart.namespace,
armada_chart_info)
new_overrides = self._add_armada_override_header(
chart.name, metadata_name, repo_name, chart_tarfile,
chart.namespace, user_overrides[chart.namespace])
user_overrides[chart.namespace] = new_overrides
metadata_name, repo_name, chart_tarfile =\
self._get_chart_info_from_armada_chart(chart.name, chart.namespace,
chart_info)
new_overrides = self._add_armada_override_header(
chart.name, metadata_name, repo_name, chart_tarfile,
chart.namespace, user_overrides[chart.namespace])
user_overrides[chart.namespace] = new_overrides
self._write_chart_overrides(path, chart.name,
cnamespace, user_overrides)
if not is_fluxcd_app:
# Write the manifest doc overrides, a summmary file for easy --value
# generation on the apply, and a unified manifest for deletion.
manifest_op.save_overrides()
manifest_op.save_summary(path=path)
manifest_op.save_delete_manifest()
# Write the manifest doc overrides, a summmary file for easy --value
# generation on the apply, and a unified manifest for deletion.
manifest_op.save_overrides()
manifest_op.save_summary(path=path)
manifest_op.save_delete_manifest()
@helm_context
def _generate_helm_application_overrides_fluxcd(self, path, app_name,
mode=None,
cnamespace=None,
chart_info=None,
combined=False):
"""Create the system overrides files for a supported application
This method will generate system helm chart overrides yaml files for a
set of supported charts that comprise an application. If the namespace
is provided only the overrides files for that specified namespace will
be written.
:param app_name: name of the bundle of charts required to support an
application
:param mode: mode to control how to apply application manifest
:param cnamespace: (optional) namespace
:param chart_info: (optional) supporting chart information
extracted from the fluxcd manifests which is used to influence
overrides
:param combined: (optional) whether to apply user overrides on top of
system overrides
"""
app, plugin_name = self._find_kube_app_and_app_plugin_name(app_name)
# Get a kustomize operator to provide a single point of
# manipulation for the chart resources
kustomize_op = self.get_fluxcd_kustomize_operator(app.name)
# Load the FluxCD manifests into the operator
fluxcd_manifests_dir = utils.generate_synced_fluxcd_manifests_fqpn(
app.name, app.app_version)
kustomize_op.load(fluxcd_manifests_dir)
if plugin_name in self.helm_system_applications:
app_overrides = self._get_helm_application_overrides(plugin_name,
cnamespace)
for (chart_name, overrides) in iteritems(app_overrides):
if combined:
# The overrides at this point are the system overrides. For
# charts with multiple namespaces, the overrides would
# contain multiple keys, one for each namespace.
#
# Retrieve the user overrides of each namespace from the
# database and merge this list of user overrides, if they
# exist, with the system overrides. Both system and user
# override contents are then merged based on the namespace,
# prepended with required header and written to
# corresponding files (<namespace>-<chart>.yaml).
file_overrides = []
for chart_namespace in overrides.keys():
try:
db_chart = self.dbapi.helm_override_get(
app.id, chart_name, chart_namespace)
db_user_overrides = db_chart.user_overrides
if db_user_overrides:
file_overrides.append(yaml.dump(
{chart_namespace: yaml.load(db_user_overrides)}))
except exception.HelmOverrideNotFound:
pass
if file_overrides:
# Use dump() instead of safe_dump() as the latter is
# not agreeable with password regex in some overrides
system_overrides = yaml.dump(overrides)
file_overrides.insert(0, system_overrides)
combined_overrides = self.merge_overrides(
file_overrides=file_overrides)
overrides = yaml.load(combined_overrides)
self._write_chart_overrides(path, chart_name, cnamespace, overrides)
# Update manifest docs based on the plugin directives. If the
# application does not provide a manifest operator, the
# GenericFluxCDKustomizeOperator is used and chart specific
# operations can be skipped.
if kustomize_op.APP:
if chart_name in self.chart_operators:
self.chart_operators[chart_name].execute_kustomize_updates(
kustomize_op)
# Update the kustomization manifests based on platform conditions
kustomize_op.platform_mode_kustomize_updates(self.dbapi, mode)
else:
# Generic applications
for chart in chart_info:
try:
db_chart = self.dbapi.helm_override_get(
app.id, chart.name, chart.namespace)
except exception.HelmOverrideNotFound:
# This routine is to create helm overrides entries
# in database during application-upload so that user
# can list the supported helm chart overrides of the
# application via helm-override-list
try:
values = {
'name': chart.name,
'namespace': chart.namespace,
'app_id': app.id,
}
db_chart = self.dbapi.helm_override_create(values=values)
except Exception as e:
LOG.exception(e)
return
user_overrides = {chart.namespace: {}}
db_user_overrides = db_chart.user_overrides
if db_user_overrides:
user_overrides = yaml.load(yaml.dump(
{chart.namespace: yaml.load(db_user_overrides)}))
self._write_chart_overrides(path, chart.name,
cnamespace, user_overrides)
# Write the kustomization doc overrides and a unified manifest for deletion.
kustomize_op.save_kustomization_updates()
kustomize_op.save_release_cleanup_data()
def _find_kube_app_and_app_plugin_name(self, app_name):
return utils.find_kube_app(self.dbapi, app_name), \

View File

@ -0,0 +1,285 @@
#
# Copyright (c) 2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# All Rights Reserved.
#
""" System inventory FluxCD Kustomize manifest operator."""
import abc
import io
import json
import os
import ruamel.yaml as yaml
import shutil
import six
import tempfile
from copy import deepcopy
from oslo_log import log as logging
from sysinv.common import constants
LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class FluxCDKustomizeOperator(object):
def __init__(self, manifest_fqpn=None):
self.app_manifest_path = None # Path to the app manifests
self.original_kustomization_fqpn = None # Original kustomization.yaml
self.kustomization_fqpn = None # Updated kustomization.yaml
self.release_cleanup_fqpn = None # Helm release cleanup data
self.kustomization_content = [] # Original app manifest content
self.chart_to_resource_map = {} # Dict used to disable charts
self.kustomization_resources = [] # Kustomize resource list
self.kustomization_namespace = None # Kustomize global namespace
self.chart_cleanup = [] # List of disabled charts
if manifest_fqpn:
self.load(manifest_fqpn)
def __str__(self):
return json.dumps({
constants.APP_ROOT_KUSTOMIZE_FILE: self.kustomization_content,
'chart_to_resource_map': self.chart_to_resource_map,
'chart_cleanup': self.chart_cleanup,
}, indent=2)
def load(self, manifests_dir_fqpn):
""" Load the application kustomization manifests for processing
:param manifest_fqpn: fully qualified path name of the application
manifests directory
"""
# Make sure that the manifests directory exists
if not os.path.exists(manifests_dir_fqpn):
LOG.error("Kustomize manifest directory %s does not exist" %
manifests_dir_fqpn)
return
# Save the location of the application manifests
self.app_manifest_path = manifests_dir_fqpn
# Make sure that the kustomization.yaml file exists
self.kustomization_fqpn = os.path.join(
manifests_dir_fqpn, constants.APP_ROOT_KUSTOMIZE_FILE)
if not os.path.exists(self.kustomization_fqpn):
LOG.error("Kustomize manifest %s does not exist" %
self.kustomization_fqpn)
return
# Save the original kustomization.yaml for
self.original_kustomization_fqpn = "%s-orig%s" % os.path.splitext(
self.kustomization_fqpn)
if not os.path.exists(self.original_kustomization_fqpn):
shutil.copy(self.kustomization_fqpn,
self.original_kustomization_fqpn)
# Save the helm release cleanup data file name
self.release_cleanup_fqpn = os.path.join(
manifests_dir_fqpn, constants.APP_RELEASE_CLEANUP_FILE)
# Reset the view of charts to cleanup as platform conditions may have
# changed
self.chart_cleanup = []
# Read the original kustomization.yaml content
with io.open(self.original_kustomization_fqpn, 'r', encoding='utf-8') as f:
# The RoundTripLoader removes the superfluous quotes by default,
# Set preserve_quotes=True to preserve all the quotes.
self.kustomization_content = list(yaml.load_all(
f, Loader=yaml.RoundTripLoader, preserve_quotes=True))
# Expect the top level kustomization.yaml to only have one doc
if len(self.kustomization_content) > 1:
LOG.error("Malformed Kustomize manifest %s contains more than one yaml "
"doc." % self.kustomization_fqpn)
return
# Grab the app resource
self.kustomization_resources = self.kustomization_content[0]['resources']
# Grab the global namespace
self.kustomization_namespace = deepcopy(
self.kustomization_content[0]['namespace'])
# For these resources, find the HelmRelease info and build a resource
# map
for resource in self.kustomization_resources:
# expect a helrelease.yaml flle to be present in a helm resource
# directory
# is the resource a directory?
resource_fqpn = os.path.join(manifests_dir_fqpn, resource)
if not os.path.isdir(resource_fqpn):
LOG.debug("%s is not a directory and cannot contain HelmRelease "
"info. skipping" % resource_fqpn)
continue
# is a helm release present?
helm_release_fqpn = os.path.join(resource_fqpn, "helmrelease.yaml")
if os.path.isfile(helm_release_fqpn):
with io.open(helm_release_fqpn, 'r', encoding='utf-8') as f:
helm_release_doc = list(yaml.load_all(f,
Loader=yaml.RoundTripLoader, preserve_quotes=True))
if len(helm_release_doc) > 1:
LOG.error("Malformed HelmRelease: %s contains more than one "
"yaml doc." % helm_release_fqpn)
continue
# get the HelmRelease name
try:
metadata_name = helm_release_doc[0]['metadata']['name']
except Exception:
LOG.error("Malformed HelmRelease: Unable to retreive the "
"metadata name from %s" % helm_release_fqpn)
continue
# get the chart name
try:
chart_name = \
helm_release_doc[0]['spec']['chart']['spec']['chart']
except Exception:
LOG.error("Malformed HelmRelease: Unable to retreive the "
"chart name from %s" % helm_release_fqpn)
continue
# Save pertinent data for disabling chart resources and cleaning
# up existing helm releases after being disabled
self.chart_to_resource_map.update({
chart_name: {'resource': resource,
'metadata_name': metadata_name}})
else:
LOG.debug("Expecting to find a HelmRelease file at {}, skipping "
"resource {}.".format(helm_release_fqpn,
resource_fqpn))
LOG.debug("chart_to_resource_map: {}".format(self.chart_to_resource_map))
def _delete_kustomization_file(self):
""" Remove any previously written top level kustomization file
"""
if self.kustomization_fqpn and os.path.exists(self.kustomization_fqpn):
os.remove(self.kustomization_fqpn)
def _delete_release_cleanup_file(self):
""" Remove any previously written helm release cleanup information
"""
if self.release_cleanup_fqpn and os.path.exists(self.release_cleanup_fqpn):
os.remove(self.release_cleanup_fqpn)
def _write_file(self, path, filename, pathfilename, data):
""" Write a yaml file
:param path: path to write the file
:param filename: name of the file
:param pathfilename: FQPN of the file
:param data: file data
"""
try:
fd, tmppath = tempfile.mkstemp(dir=path, prefix=filename,
text=True)
with open(tmppath, 'w') as f:
yaml.dump(data, f, Dumper=yaml.RoundTripDumper,
default_flow_style=False)
os.close(fd)
os.rename(tmppath, pathfilename)
# Change the permission to be readable to non-root
# users
os.chmod(pathfilename, 0o644)
except Exception:
if os.path.exists(tmppath):
os.remove(tmppath)
LOG.exception("Failed to write meta overrides %s" % pathfilename)
raise
def save_kustomization_updates(self):
""" Save an updated top level kustomization.yaml"""
if self.kustomization_fqpn and os.path.exists(self.kustomization_fqpn):
# remove existing kustomization file
self._delete_kustomization_file()
# Save the updated view of the resource to enable
self.kustomization_content[0]['resources'] = self.kustomization_resources
with open(self.kustomization_fqpn, 'w') as f:
try:
yaml.dump_all(self.kustomization_content, f, Dumper=yaml.RoundTripDumper,
explicit_start=True,
default_flow_style=False)
LOG.debug("Updated kustomization file %s generated" %
self.kustomization_fqpn)
except Exception as e:
LOG.error("Failed to generate updated kustomization file %s: "
"%s" % (self.kustomization_fqpn, e))
else:
LOG.error("Kustomization file %s does not exist" % self.kustomization_fqpn)
def save_release_cleanup_data(self):
""" Save yaml to cleanup HelmReleases that are no longer managed."""
# remove existing helm release file
self._delete_release_cleanup_file()
if self.chart_cleanup:
cleanup_dict = {'releases': self.chart_cleanup}
self._write_file(self.app_manifest_path,
constants.APP_RELEASE_CLEANUP_FILE,
self.release_cleanup_fqpn,
cleanup_dict)
else:
LOG.info("%s is not needed. All charts are enabled." % self.release_cleanup_fqpn)
def helm_release_resource_delete(self, chart):
""" Delete a helm release resource
This method will remove a chart's resource from the top level
kustomization file which will prevent it from being created during
application applies.
The chart will also be added to a list of charts that will have their
existing helm releases cleaned up
:param chart: chart name to remove from the resource list
"""
removed_resource = self.chart_to_resource_map.pop(chart, None)
if removed_resource:
# Remove the resource from the known resource list
self.kustomization_resources.remove(removed_resource['resource'])
# Save the info needed to clean up any existing chart release
self.chart_cleanup.append({
'namespace': self.kustomization_namespace,
'name': removed_resource['metadata_name']
})
else:
LOG.error("%s is an unknown chart resource to %s" % (
chart, self.original_kustomization_fqpn))
@abc.abstractmethod
def platform_mode_kustomize_updates(self, dbapi, mode):
""" Update the top-level kustomization resource list
Make changes to the top-level kustomization resource list based on the
platform mode
:param dbapi: DB api object
:param mode: mode to control when to update the resource list
"""
pass

View File

@ -0,0 +1,24 @@
#
# Copyright (c) 2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# All Rights Reserved.
#
""" System inventory Generic FluxCD Kustomize operator."""
from sysinv.helm import kustomize_base as base
class GenericFluxCDKustomizeOperator(base.FluxCDKustomizeOperator):
APP = None
def platform_mode_kustomize_updates(self, dbapi, mode):
""" Update the application kustomization manifests based on the platform
:param dbapi: DB api object
:param mode: mode to control how to apply the application manifest
"""
pass

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (c) 2019-2021 Wind River Systems, Inc.
# Copyright (c) 2019-2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -213,7 +213,7 @@ class ArmadaManifestOperator(object):
was updated into an overrides file. The files are written to the same
directory as the application manifest.
"""
if os.path.exists(self.manifest_path):
if self.manifest_path and os.path.exists(self.manifest_path):
# cleanup any existing meta override files
self._cleanup_meta_files(self.manifest_path)
@ -242,7 +242,7 @@ class ArmadaManifestOperator(object):
clear view of the conditional changes that were enforced by the system
in the plugins
"""
if os.path.exists(self.manifest_path):
if self.manifest_path and os.path.exists(self.manifest_path):
# cleanup existing deletion manifest
self._cleanup_deletion_manifest()