Application dirs and overrides updates

This commit includes the following changes to support updating
versioned application:
  - helm application overrides are tied to a specific application
  - each application files are uploaded to its own versioned directory

    e.g. stx-openstack-1.0-13 app files will be located at,
         /opt/platform/armada/19.01/stx-openstack/1.0-13/...
         /opt/platform/helm/19.01/stx-openstack/1.0-13/...
         /scratch/apps/stx-openstack/1.0-13/...

Story: 2005350
Task: 33439
Change-Id: I75555deda57181d069f24d458dda5bf08e7e17cc
Signed-off-by: Angie Wang <angie.wang@windriver.com>
This commit is contained in:
Angie Wang 2019-05-17 16:43:12 -04:00
parent 07587a049a
commit b978111f19
16 changed files with 270 additions and 152 deletions

View File

@ -1,2 +1,2 @@
SRC_DIR="cgts-client"
TIS_PATCH_VER=65
TIS_PATCH_VER=66

View File

@ -7,6 +7,7 @@
#
from cgtsclient.common import base
from cgtsclient import exc
class App(base.Resource):
@ -66,3 +67,12 @@ class AppManager(base.Manager):
:param name: app_name
"""
return self._delete(self._path(app_name))
def _find_app(cc, app_name):
try:
app = cc.app.get(app_name)
except exc.HTTPNotFound:
raise exc.CommandError('Application not found: %s' % app_name)
else:
return app

View File

@ -21,17 +21,18 @@ class HelmManager(base.Manager):
def _path(name=''):
return '/v1/helm_charts/%s' % name
def list_charts(self):
def list_charts(self, app):
"""Get list of charts
For each chart it will show any overrides for that chart along
with the namespace of the overrides.
"""
return self._list(self._path(), 'charts')
return self._list(self._path() + '?app_name=' + app, 'charts')
def get_overrides(self, name, namespace):
def get_overrides(self, app, name, namespace):
"""Get overrides for a given chart.
:param app_name: name of application
:param name: name of the chart
:param namespace: namespace for the chart overrides
@ -39,14 +40,17 @@ class HelmManager(base.Manager):
specified chart.
"""
try:
return self._list(self._path(name) + '?namespace=' + namespace)[0]
return self._list(self._path(app) +
'?name=' + name +
'&namespace=' + namespace)[0]
except IndexError:
return None
def update_overrides(self, name, namespace,
def update_overrides(self, app, name, namespace,
flag='reset', override_values={}):
"""Update overrides for a given chart.
:param app_name: name of application
:param name: name of the chart
:param namespace: namespace for the chart overrides
:param flag: 'reuse' or 'reset' to indicate how to handle existing
@ -56,12 +60,17 @@ class HelmManager(base.Manager):
This will return the end-user overrides for the specified chart.
"""
body = {'flag': flag, 'values': override_values}
return self._update(self._path(name) + '?namespace=' + namespace, body)
return self._update(self._path(app) +
'?name=' + name +
'&namespace=' + namespace, body)
def delete_overrides(self, name, namespace):
def delete_overrides(self, app, name, namespace):
"""Delete overrides for a given chart.
:param app_name: name of application
:param name: name of the chart
:param namespace: namespace for the chart overrides
"""
return self._delete(self._path(name) + '?namespace=' + namespace)
return self._delete(self._path(app) +
'?name=' + name +
'&namespace=' + namespace)

View File

@ -11,6 +11,7 @@ import yaml
from cgtsclient.common import utils
from cgtsclient import exc
from cgtsclient.v1 import app as app_utils
def _print_helm_chart(chart):
@ -22,12 +23,32 @@ def _print_helm_chart(chart):
utils.print_dict(ordereddata)
def _find_overrides(cc, app, chart, namespace):
charts = cc.helm.list_charts(app.name)
for c in charts:
if chart == c.name and namespace in c.namespaces:
break
else:
raise exc.CommandError('Chart overrides %s:%s for application '
'%s not found' %
(chart, namespace, app.name))
return c
@utils.arg('app',
metavar='<app name>',
help="Name of the application")
def do_helm_override_list(cc, args):
"""List system helm charts."""
charts = cc.helm.list_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)
@utils.arg('app',
metavar='<app name>',
help="Name of the application")
@utils.arg('chart', metavar='<chart name>',
help="Name of chart")
@utils.arg('namespace',
@ -35,14 +56,15 @@ def do_helm_override_list(cc, args):
help="namespace of chart overrides")
def do_helm_override_show(cc, args):
"""Show overrides for chart."""
try:
chart = cc.helm.get_overrides(args.chart, args.namespace)
_print_helm_chart(chart)
except exc.HTTPNotFound:
raise exc.CommandError('chart overrides not found: %s:%s' % (
args.chart, args.namespace))
app = app_utils._find_app(cc, args.app)
_find_overrides(cc, app, args.chart, args.namespace)
chart = cc.helm.get_overrides(args.app, args.chart, args.namespace)
_print_helm_chart(chart)
@utils.arg('app',
metavar='<app name>',
help="Name of the application")
@utils.arg('chart',
metavar='<chart name>',
help="Name of chart")
@ -51,15 +73,16 @@ def do_helm_override_show(cc, args):
help="namespace of chart overrides")
def do_helm_override_delete(cc, args):
"""Delete overrides for a chart."""
try:
cc.helm.delete_overrides(args.chart, args.namespace)
print('Deleted chart overrides for %s:%s' % (
args.chart, args.namespace))
except exc.HTTPNotFound:
raise exc.CommandError('chart overrides not found: %s:%s' % (
args.chart, args.namespace))
app = app_utils._find_app(cc, args.app)
_find_overrides(cc, app, args.chart, args.namespace)
cc.helm.delete_overrides(args.app, args.chart, args.namespace)
print('Deleted chart overrides %s:%s for application %s' %
(args.chart, args.namespace, args.app))
@utils.arg('app',
metavar='<app name>',
help="Name of the application")
@utils.arg('chart',
metavar='<chart name>',
help="Name of chart")
@ -85,6 +108,9 @@ def do_helm_override_delete(cc, args):
def do_helm_override_update(cc, args):
"""Update helm chart user overrides."""
app = app_utils._find_app(cc, args.app)
_find_overrides(cc, app, args.chart, args.namespace)
# This logic results in similar behaviour to "helm upgrade".
flag = 'reset'
if args.reuse_values and not args.reset_values:
@ -114,10 +140,6 @@ def do_helm_override_update(cc, args):
'set': override_set,
}
try:
chart = cc.helm.update_overrides(args.chart, args.namespace,
flag, overrides)
except exc.HTTPNotFound:
raise exc.CommandError('helm chart not found: %s:%s' % (
args.chart, args.namespace))
chart = cc.helm.update_overrides(args.app, args.chart, args.namespace,
flag, overrides)
_print_helm_chart(chart)

View File

@ -1,2 +1,2 @@
SRC_DIR="sysinv"
TIS_PATCH_VER=318
TIS_PATCH_VER=319

View File

@ -23,30 +23,28 @@ LOG = log.getLogger(__name__)
class HelmChartsController(rest.RestController):
@wsme_pecan.wsexpose(wtypes.text)
def get_all(self):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def get_all(self, app_name):
"""Provides information about the available charts to override."""
supported_apps = pecan.request.rpcapi.get_helm_applications(
pecan.request.context)
all_charts = {}
for app in supported_apps:
namespaces = pecan.request.rpcapi.get_helm_application_namespaces(
pecan.request.context, app)
for chart in namespaces:
if chart not in all_charts:
all_charts[chart] = namespaces[chart]
else:
all_charts[chart] = list(set().union(all_charts[chart],
namespaces[chart]))
try:
objects.kube_app.get_by_name(
pecan.request.context, app_name)
except exception.KubeAppNotFound:
raise wsme.exc.ClientSideError(_("Application %s not found." % app_name))
namespaces = pecan.request.rpcapi.get_helm_application_namespaces(
pecan.request.context, app_name)
charts = [{'name': chart, 'namespaces': namespaces[chart]}
for chart in namespaces]
charts = [{'name': c, 'namespaces': ns} for c, ns in all_charts.items()]
return {'charts': charts}
@wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text)
def get_one(self, name, namespace):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text, wtypes.text)
def get_one(self, app_name, name, namespace):
"""Retrieve information about the given chart.
:param app_name: name of application
:param name: name of helm chart
:param namespace: namespace of chart overrides
"""
@ -54,9 +52,13 @@ class HelmChartsController(rest.RestController):
# Get any user-specified overrides.
try:
db_chart = objects.helm_overrides.get_by_name(
pecan.request.context, name, namespace)
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, name, namespace)
user_overrides = db_chart.user_overrides
except exception.KubeAppNotFound:
raise wsme.exc.ClientSideError(_("Application %s not found." % app_name))
except exception.HelmOverrideNotFound:
user_overrides = ''
@ -92,10 +94,12 @@ class HelmChartsController(rest.RestController):
if not namespace:
raise wsme.exc.ClientSideError(_("Namespace must be specified."))
@wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text, wtypes.text, wtypes.text)
def patch(self, name, namespace, flag, values):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text,
wtypes.text, wtypes.text, wtypes.text)
def patch(self, app_name, name, namespace, flag, values):
""" Update user overrides.
:param app_name: name of application
:param name: chart name
:param namespace: namespace of chart overrides
:param flag: one of "reuse" or "reset", describes how to handle
@ -110,15 +114,20 @@ class HelmChartsController(rest.RestController):
# Get any stored user overrides for this chart. We'll need this
# object later either way.
try:
db_chart = objects.helm_overrides.get_by_name(
pecan.request.context, name, namespace)
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, name, namespace)
except exception.KubeAppNotFound:
raise wsme.exc.ClientSideError(_("Application %s not found." % app_name))
except exception.HelmOverrideNotFound:
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)
'user_overrides': '',
'app_id': app.id})
db_chart = objects.helm_overrides.get_by_appid_name(
pecan.request.context, app.id, name, namespace)
if flag == 'reuse':
if db_chart.user_overrides is not None:
@ -150,16 +159,21 @@ class HelmChartsController(rest.RestController):
return chart
@wsme_pecan.wsexpose(None, wtypes.text, wtypes.text, status_code=204)
def delete(self, name, namespace):
@wsme_pecan.wsexpose(None, wtypes.text, wtypes.text,
wtypes.text, status_code=204)
def delete(self, app_name, name, namespace):
"""Delete user overrides for a chart
:param app_name: name of application
:param name: chart name.
:param namespace: namespace of chart overrides
"""
self.validate_name_and_namespace(name, namespace)
try:
pecan.request.dbapi.helm_override_update(name, namespace,
app = objects.kube_app.get_by_name(pecan.request.context, app_name)
pecan.request.dbapi.helm_override_update(app.id, name, namespace,
{'user_overrides': None})
except exception.KubeAppNotFound:
raise wsme.exc.ClientSideError(_("Application %s not found." % app_name))
except exception.HelmOverrideNotFound:
pass

View File

@ -22,14 +22,16 @@ CONF = cfg.CONF
def create_app_overrides_action(path, app_name=None, namespace=None):
dbapi = api.get_instance()
operator = helm.HelmOperator(dbapi=dbapi, path=path)
operator.generate_helm_application_overrides(app_name, mode=None, cnamespace=namespace)
operator = helm.HelmOperator(dbapi=dbapi)
operator.generate_helm_application_overrides(path, app_name, mode=None,
cnamespace=namespace)
def create_armada_app_overrides_action(path, app_name=None, namespace=None):
dbapi = api.get_instance()
operator = helm.HelmOperator(dbapi=dbapi, path=path)
operator.generate_helm_application_overrides(app_name, mode=None, cnamespace=namespace,
operator = helm.HelmOperator(dbapi=dbapi)
operator.generate_helm_application_overrides(path, app_name, mode=None,
cnamespace=namespace,
armada_format=True,
armada_chart_info=None,
combined=False)
@ -37,8 +39,8 @@ def create_armada_app_overrides_action(path, app_name=None, namespace=None):
def create_chart_override_action(path, chart_name=None, namespace=None):
dbapi = api.get_instance()
operator = helm.HelmOperator(dbapi=dbapi, path=path)
operator.generate_helm_chart_overrides(chart_name, namespace)
operator = helm.HelmOperator(dbapi=dbapi)
operator.generate_helm_chart_overrides(path, chart_name, namespace)
def add_action_parsers(subparsers):

View File

@ -67,23 +67,30 @@ DOCKER_REGISTRY_SECRET = 'default-registry-key'
# Helper functions
def generate_armada_manifest_filename(app_name, manifest_filename):
return os.path.join('/manifests', app_name + '-' + manifest_filename)
def generate_armada_manifest_filename_abs(app_name, manifest_filename):
return os.path.join(constants.APP_SYNCED_DATA_PATH,
def generate_armada_manifest_filename(app_name, app_version, manifest_filename):
return os.path.join('/manifests', app_name, app_version,
app_name + '-' + manifest_filename)
def generate_manifest_filename_abs(app_name, manifest_filename):
def generate_armada_manifest_dir(app_name, app_version):
return os.path.join(constants.APP_SYNCED_DATA_PATH, app_name, app_version)
def generate_armada_manifest_filename_abs(armada_mfile_dir, app_name, manifest_filename):
return os.path.join(armada_mfile_dir, app_name + '-' + manifest_filename)
def generate_manifest_filename_abs(app_name, app_version, manifest_filename):
return os.path.join(constants.APP_INSTALL_PATH,
app_name, manifest_filename)
app_name, app_version, manifest_filename)
def generate_images_filename_abs(app_name):
return os.path.join(constants.APP_SYNCED_DATA_PATH,
app_name + '-images.yaml')
def generate_images_filename_abs(armada_mfile_dir, app_name):
return os.path.join(armada_mfile_dir, app_name + '-images.yaml')
def generate_overrides_dir(app_name, app_version):
return os.path.join(common.HELM_OVERRIDES_PATH, app_name, app_version)
def create_app_path(path):
@ -134,18 +141,20 @@ class AppOperator(object):
def _cleanup(self, app):
"""" Remove application directories and override files """
try:
if app.system_app and app.status != constants.APP_UPLOAD_FAILURE:
self._remove_chart_overrides(app.armada_mfile_abs)
if os.path.exists(app.overrides_dir):
shutil.rmtree(os.path.dirname(
app.overrides_dir))
if os.path.exists(app.armada_mfile_abs):
os.unlink(app.armada_mfile_abs)
if os.path.exists(app.imgfile_abs):
os.unlink(app.imgfile_abs)
if os.path.exists(app.armada_mfile_dir):
shutil.rmtree(os.path.dirname(
app.armada_mfile_dir))
if os.path.exists(app.path):
shutil.rmtree(app.path)
shutil.rmtree(os.path.dirname(
app.path))
except OSError as e:
LOG.error(e)
raise
def _update_app_status(self, app, new_status=None, new_progress=None):
""" Persist new app status """
@ -244,10 +253,13 @@ class AppOperator(object):
orig_uid, orig_gid = get_app_install_root_path_ownership()
try:
# One time set up of Armada manifest path for the system
# One time set up of base armada manifest path for the system
if not os.path.isdir(constants.APP_SYNCED_DATA_PATH):
os.makedirs(constants.APP_SYNCED_DATA_PATH)
if not os.path.isdir(app.armada_mfile_dir):
os.makedirs(app.armada_mfile_dir)
if not os.path.isdir(app.path):
create_app_path(app.path)
@ -307,7 +319,7 @@ class AppOperator(object):
image_tags.extend(ids)
return list(set(image_tags))
def _get_image_tags_by_charts(self, app_images_file, app_manifest_file):
def _get_image_tags_by_charts(self, app_images_file, app_manifest_file, overrides_dir):
""" Mine the image tags for charts from the images file. Add the
image tags to the manifest file if the image tags from the charts
do not exist in both overrides file and manifest file. Convert
@ -349,7 +361,7 @@ class AppOperator(object):
# Get the image tags from the overrides file
overrides = chart_namespace + '-' + chart_name + '.yaml'
app_overrides_file = os.path.join(common.HELM_OVERRIDES_PATH, overrides)
app_overrides_file = os.path.join(overrides_dir, overrides)
if os.path.exists(app_overrides_file):
try:
with open(app_overrides_file, 'r') as f:
@ -443,12 +455,12 @@ class AppOperator(object):
LOG.info("Generating application overrides...")
app.charts = self._get_list_of_charts(app.armada_mfile_abs)
self._helm.generate_helm_application_overrides(
app.name, mode=None, cnamespace=None, armada_format=True,
armada_chart_info=app.charts, combined=True)
app.overrides_dir, app.name, mode=None, cnamespace=None,
armada_format=True, armada_chart_info=app.charts, combined=True)
self._save_images_list_by_charts(app)
# Get the list of images from the updated images overrides
images_to_download = self._get_image_tags_by_charts(
app.imgfile_abs, app.armada_mfile_abs)
app.imgfile_abs, app.armada_mfile_abs, app.overrides_dir)
else:
# For custom apps, mine image tags from application path
images_to_download = self._get_image_tags_by_path(app.path)
@ -505,7 +517,7 @@ class AppOperator(object):
saved_images_list = self._retrieve_images_list(app.imgfile_abs)
saved_download_images_list = list(saved_images_list.get("download_images"))
images_to_download = self._get_image_tags_by_charts(
app.imgfile_abs, app.armada_mfile_abs)
app.imgfile_abs, app.armada_mfile_abs, app.overrides_dir)
if set(saved_download_images_list) != set(images_to_download):
saved_images_list.update({"download_images": images_to_download})
with open(app.imgfile_abs, 'wb') as f:
@ -858,7 +870,7 @@ class AppOperator(object):
pass
return charts
def _get_overrides_files(self, charts, app_name, mode):
def _get_overrides_files(self, overrides_dir, charts, app_name, mode):
"""Returns list of override files or None, used in
application-install and application-delete."""
@ -867,8 +879,7 @@ class AppOperator(object):
for chart in charts:
overrides = chart.namespace + '-' + chart.name + '.yaml'
overrides_file = os.path.join(common.HELM_OVERRIDES_PATH,
overrides)
overrides_file = os.path.join(overrides_dir, overrides)
if not os.path.exists(overrides_file):
missing_overrides.append(overrides_file)
else:
@ -881,8 +892,7 @@ class AppOperator(object):
chart.name, chart.namespace, app_name, mode):
overrides = chart.namespace + '-' + chart.name + \
'-meta' + '.yaml'
overrides_file = os.path.join(common.HELM_OVERRIDES_PATH,
overrides)
overrides_file = os.path.join(overrides_dir, overrides)
if not os.path.exists(overrides_file):
missing_overrides.append(overrides_file)
else:
@ -893,15 +903,17 @@ class AppOperator(object):
return None
return available_overrides
def _generate_armada_overrides_str(self, overrides_files):
return " ".join([' --values /overrides/{0}'.format(os.path.basename(i))
def _generate_armada_overrides_str(self, app_name, app_version, overrides_files):
return " ".join([' --values /overrides/{0}/{1}/{2}'.format(app_name, app_version,
os.path.basename(i))
for i in overrides_files])
def _remove_chart_overrides(self, manifest_file):
def _remove_chart_overrides(self, overrides_dir, manifest_file):
charts = self._get_list_of_charts(manifest_file)
for chart in charts:
if chart.name in self._helm.chart_operators:
self._helm.remove_helm_chart_overrides(chart.name,
self._helm.remove_helm_chart_overrides(overrides_dir,
chart.name,
chart.namespace)
def _make_armada_request_with_monitor(self, app, request, overrides_str=None):
@ -1129,10 +1141,10 @@ class AppOperator(object):
self._upload_helm_charts(app)
self._save_images_list(app)
self._update_app_status(app, constants.APP_UPLOAD_SUCCESS)
if app.patch_dependencies:
self._app._patch_report_app_dependencies(
app.name, app.patch_dependencies)
self._update_app_status(app, constants.APP_UPLOAD_SUCCESS)
LOG.info("Application (%s) upload completed." % app.name)
except exception.KubeAppUploadFailure as e:
LOG.exception(e)
@ -1182,16 +1194,19 @@ class AppOperator(object):
app, new_progress=constants.APP_PROGRESS_GENERATE_OVERRIDES)
LOG.info("Generating application overrides...")
self._helm.generate_helm_application_overrides(
app.name, mode, cnamespace=None, armada_format=True,
armada_chart_info=app.charts, combined=True)
overrides_files = self._get_overrides_files(app.charts, app.name, mode)
app.overrides_dir, app.name, mode, cnamespace=None,
armada_format=True, armada_chart_info=app.charts, combined=True)
overrides_files = self._get_overrides_files(app.overrides_dir,
app.charts,
app.name, mode)
if overrides_files:
LOG.info("Application overrides generated.")
# Ensure all chart overrides are readable by Armada
for file in overrides_files:
os.chmod(file, 0o644)
overrides_str =\
self._generate_armada_overrides_str(overrides_files)
self._generate_armada_overrides_str(app.name, app.version,
overrides_files)
self._update_app_status(
app, new_progress=constants.APP_PROGRESS_DOWNLOAD_IMAGES)
self._download_images(app)
@ -1321,22 +1336,33 @@ class AppOperator(object):
def __init__(self, rpc_app, is_system_app):
self._kube_app = rpc_app
self.path = os.path.join(constants.APP_INSTALL_PATH,
self._kube_app.get('name'))
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.charts_dir = os.path.join(self.path, 'charts')
self.images_dir = os.path.join(self.path, 'images')
self.tarfile = None
self.downloaded_tarfile = False
self.system_app = is_system_app
self.overrides_dir = generate_overrides_dir(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.armada_mfile_dir = generate_armada_manifest_dir(
self._kube_app.get('name'),
self._kube_app.get('app_version'))
self.armada_mfile = generate_armada_manifest_filename(
self._kube_app.get('name'),
self._kube_app.get('app_version'),
self._kube_app.get('manifest_file'))
self.armada_mfile_abs = generate_armada_manifest_filename_abs(
self.armada_mfile_dir,
self._kube_app.get('name'),
self._kube_app.get('manifest_file'))
self.mfile_abs = generate_manifest_filename_abs(
self._kube_app.get('name'),
self._kube_app.get('app_version'),
self._kube_app.get('manifest_file'))
self.imgfile_abs = generate_images_filename_abs(
self.armada_mfile_dir,
self._kube_app.get('name'))
self.patch_dependencies = []
@ -1379,25 +1405,35 @@ class AppOperator(object):
self._kube_app.manifest_name = new_mname
self._kube_app.manifest_file = new_mfile
self.armada_mfile = generate_armada_manifest_filename(
self.name, new_mfile)
self.name, self.version, new_mfile)
self.armada_mfile_abs = generate_armada_manifest_filename_abs(
self.name, new_mfile)
self.armada_mfile_dir, self.name, new_mfile)
self.mfile_abs = generate_manifest_filename_abs(
self.name, new_mfile)
self.name, self.version, new_mfile)
def regenerate_application_info(self, new_name, new_version, new_patch_dependencies):
self._kube_app.name = new_name
self._kube_app.app_version = new_version
self.system_app = \
(self.name == constants.HELM_APP_OPENSTACK)
self.imgfile_abs = \
generate_images_filename_abs(self.name)
new_armada_dir = generate_armada_manifest_dir(
self.name, self.version)
shutil.move(self.armada_mfile_dir, new_armada_dir)
shutil.rmtree(os.path.dirname(self.armada_mfile_dir))
self.armada_mfile_dir = new_armada_dir
new_path = os.path.join(
constants.APP_INSTALL_PATH, self.name)
os.rename(self.path, new_path)
constants.APP_INSTALL_PATH, self.name, self.version)
shutil.move(self.path, new_path)
shutil.rmtree(os.path.dirname(self.path))
self.path = new_path
self.charts_dir = os.path.join(self.path, 'charts')
self.images_dir = os.path.join(self.path, 'images')
self.imgfile_abs = \
generate_images_filename_abs(self.armada_mfile_dir, self.name)
self.overrides_dir = generate_overrides_dir(self.name, self.version)
self.patch_dependencies = new_patch_dependencies

View File

@ -7358,9 +7358,10 @@ class Connection(api.Connection):
raise exception.CertificateNotFound(uuid)
query.delete()
def _helm_override_get(self, name, namespace):
def _helm_override_get(self, app_id, name, namespace):
query = model_query(models.HelmOverrides)
query = query.filter_by(name=name, namespace=namespace)
query = query.filter_by(
app_id=app_id, name=name, namespace=namespace)
try:
return query.one()
except NoResultFound:
@ -7382,12 +7383,13 @@ class Connection(api.Connection):
(values['name']))
raise exception.HelmOverrideAlreadyExists(
name=values['name'], namespace=values['namespace'])
return self._helm_override_get(values['name'],
return self._helm_override_get(values['app_id'],
values['name'],
values['namespace'])
@objects.objectify(objects.helm_overrides)
def helm_override_get(self, name, namespace):
return self._helm_override_get(name, namespace)
def helm_override_get(self, app_id, name, namespace):
return self._helm_override_get(app_id, name, namespace)
@objects.objectify(objects.helm_overrides)
def helm_override_get_all(self):
@ -7395,10 +7397,11 @@ class Connection(api.Connection):
return query.all()
@objects.objectify(objects.helm_overrides)
def helm_override_update(self, name, namespace, values):
def helm_override_update(self, app_id, name, namespace, values):
with _session_for_write() as session:
query = model_query(models.HelmOverrides, session=session)
query = query.filter_by(name=name, namespace=namespace)
query = query.filter_by(
app_id=app_id, name=name, namespace=namespace)
count = query.update(values, synchronize_session='fetch')
if count == 0:
@ -7406,10 +7409,11 @@ class Connection(api.Connection):
namespace=namespace)
return query.one()
def helm_override_destroy(self, name, namespace):
def helm_override_destroy(self, app_id, name, namespace):
with _session_for_write() as session:
query = model_query(models.HelmOverrides, session=session)
query = query.filter_by(name=name, namespace=namespace)
query = query.filter_by(
app_id=app_id, name=name, namespace=namespace)
try:
query.one()
@ -7573,6 +7577,7 @@ class Connection(api.Connection):
"operation is not allowed while status is " + app.status
raise exception.KubeAppDeleteFailure(
name=name,
version=app.app_version,
reason=failure_reason)
except NoResultFound:
raise exception.KubeAppNotFound(name)

View File

@ -25,7 +25,7 @@ def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
# Define and create the helm_overrides table.
# Define and create the kube_app table.
kube_app = Table(
'kube_app',
meta,

View File

@ -6,7 +6,7 @@
#
from sqlalchemy import DateTime, String, Text, Integer
from sqlalchemy import Column, MetaData, Table, UniqueConstraint
from sqlalchemy import Column, MetaData, Table, UniqueConstraint, ForeignKey
from sysinv.openstack.common import log
@ -25,6 +25,8 @@ def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
Table('kube_app', meta, autoload=True)
# Define and create the helm_overrides table.
helm_overrides = Table(
'helm_overrides',
@ -36,7 +38,9 @@ def upgrade(migrate_engine):
Column('name', String(255), nullable=False),
Column('namespace', String(255), nullable=False),
Column('user_overrides', Text, nullable=True),
UniqueConstraint('name', 'namespace', name='u_name_namespace'),
Column('app_id', Integer,
ForeignKey('kube_app.id', ondelete='CASCADE')),
UniqueConstraint('name', 'namespace', 'app_id', name='u_app_name_namespace'),
mysql_engine=ENGINE,
mysql_charset=CHARSET,

View File

@ -1677,7 +1677,9 @@ class HelmOverrides(Base):
namespace = Column(String(255), nullable=False)
user_overrides = Column(Text, nullable=True)
system_overrides = Column(JSONEncodedDict, nullable=True)
UniqueConstraint('name', 'namespace', name='u_name_namespace')
app_id = Column(Integer, ForeignKey('kube_app.id', ondelete='CASCADE'))
kube_app = relationship("KubeApp", lazy="joined", join_depth=1)
UniqueConstraint('name', 'namespace', 'app_id', name='u_app_name_namespace')
class Label(Base):

View File

@ -45,12 +45,8 @@ def helm_context(func):
class HelmOperator(object):
"""Class to encapsulate helm override operations for System Inventory"""
def __init__(self, dbapi=None, path=None):
if path is None:
path = common.HELM_OVERRIDES_PATH
def __init__(self, dbapi=None):
self.dbapi = dbapi
self.path = path
# register chart operators for lookup
self.chart_operators = {}
@ -377,7 +373,7 @@ class HelmOperator(object):
return values
@helm_context
def generate_helm_chart_overrides(self, chart_name, cnamespace=None):
def generate_helm_chart_overrides(self, path, chart_name, cnamespace=None):
"""Generate system helm chart overrides
This method will generate system helm chart override an write them to a
@ -399,7 +395,8 @@ class HelmOperator(object):
overrides = self._get_helm_chart_overrides(
chart_name,
cnamespace)
self._write_chart_overrides(chart_name,
self._write_chart_overrides(path,
chart_name,
cnamespace,
overrides)
except Exception as e:
@ -424,7 +421,8 @@ class HelmOperator(object):
return overrides
@helm_context
def generate_helm_application_overrides(self, app_name, mode=None,
def generate_helm_application_overrides(self, path, app_name,
mode=None,
cnamespace=None,
armada_format=False,
armada_chart_info=None,
@ -450,6 +448,11 @@ class HelmOperator(object):
"""
if app_name in self.helm_applications:
try:
app = self.dbapi.kube_app_get(app_name)
except exception.KubeAppNotFound:
LOG.exception("Application %s not found." % app_name)
app_overrides = self._get_helm_application_overrides(app_name,
cnamespace)
for (chart_name, overrides) in iteritems(app_overrides):
@ -468,7 +471,7 @@ class HelmOperator(object):
for chart_namespace in overrides.keys():
try:
db_chart = self.dbapi.helm_override_get(
chart_name, chart_namespace)
app.id, chart_name, chart_namespace)
db_user_overrides = db_chart.user_overrides
if db_user_overrides:
file_overrides.append(yaml.dump(
@ -495,7 +498,7 @@ class HelmOperator(object):
chart_name, armada_chart_repo_name,
key, overrides[key])
overrides[key] = new_overrides
self._write_chart_overrides(chart_name, cnamespace, overrides)
self._write_chart_overrides(path, chart_name, cnamespace, overrides)
# Write any meta-overrides for this chart. These will be in
# armada format already.
@ -507,14 +510,14 @@ class HelmOperator(object):
if overrides:
chart_meta_name = chart_name + '-meta'
self._write_chart_overrides(
chart_meta_name, cnamespace, overrides)
path, chart_meta_name, cnamespace, overrides)
elif app_name:
LOG.exception("%s application is not supported" % app_name)
else:
LOG.exception("application name is required")
def remove_helm_chart_overrides(self, chart_name, cnamespace=None):
def remove_helm_chart_overrides(self, path, chart_name, cnamespace=None):
"""Remove the overrides files for a chart"""
if chart_name in self.chart_operators:
@ -529,7 +532,7 @@ class HelmOperator(object):
for f in filenames:
try:
self._remove_overrides(f)
self._remove_overrides(path, f)
except Exception as e:
LOG.exception("failed to remove %s overrides: %s: %s" % (
chart_name, f, e))
@ -537,12 +540,12 @@ class HelmOperator(object):
LOG.exception("chart %s not supported for system overrides" %
chart_name)
def _write_chart_overrides(self, chart_name, cnamespace, overrides):
def _write_chart_overrides(self, path, chart_name, cnamespace, overrides):
"""Write a one or more overrides files for a chart. """
def _write_file(filename, values):
try:
self._write_overrides(filename, values)
self._write_overrides(path, filename, values)
except Exception as e:
LOG.exception("failed to write %s overrides: %s: %s" % (
chart_name, filename, e))
@ -553,12 +556,15 @@ class HelmOperator(object):
for ns in overrides.keys():
_write_file("%s-%s.yaml" % (ns, chart_name), overrides[ns])
def _write_overrides(self, filename, overrides):
def _write_overrides(self, path, filename, overrides):
"""Write a single overrides file. """
filepath = os.path.join(self.path, filename)
if not os.path.isdir(path):
os.makedirs(path)
filepath = os.path.join(path, filename)
try:
fd, tmppath = tempfile.mkstemp(dir=self.path, prefix=filename,
fd, tmppath = tempfile.mkstemp(dir=path, prefix=filename,
text=True)
with open(tmppath, 'w') as f:
@ -569,10 +575,10 @@ class HelmOperator(object):
LOG.exception("failed to write overrides file: %s" % filepath)
raise
def _remove_overrides(self, filename):
def _remove_overrides(self, path, filename):
"""Remove a single overrides file. """
filepath = os.path.join(self.path, filename)
filepath = os.path.join(path, filename)
try:
if os.path.exists(filepath):
os.unlink(filepath)

View File

@ -149,7 +149,9 @@ class OpenstackBaseHelm(base.BaseHelm):
return None
try:
override = self.dbapi.helm_override_get(name=chart,
app = self.dbapi.kube_app_get(constants.HELM_APP_OPENSTACK)
override = self.dbapi.helm_override_get(app_id=app.id,
name=chart,
namespace=namespace)
except exception.HelmOverrideNotFound:
# Override for this chart not found, so create one
@ -157,6 +159,7 @@ class OpenstackBaseHelm(base.BaseHelm):
values = {
'name': chart,
'namespace': namespace,
'app_id': app.id,
}
override = self.dbapi.helm_override_create(values=values)
except Exception as e:
@ -176,7 +179,7 @@ class OpenstackBaseHelm(base.BaseHelm):
})
try:
self.dbapi.helm_override_update(
name=chart, namespace=namespace, values=values)
app_id=app.id, name=chart, namespace=namespace, values=values)
except Exception as e:
LOG.exception(e)
@ -337,13 +340,16 @@ class OpenstackBaseHelm(base.BaseHelm):
def _get_or_generate_ssh_keys(self, chart, namespace):
try:
override = self.dbapi.helm_override_get(name=chart,
app = self.dbapi.kube_app_get(constants.HELM_APP_OPENSTACK)
override = self.dbapi.helm_override_get(app_id=app.id,
name=chart,
namespace=namespace)
except exception.HelmOverrideNotFound:
# Override for this chart not found, so create one
values = {
'name': chart,
'namespace': namespace,
'app_id': app.id
}
override = self.dbapi.helm_override_create(values=values)
@ -362,7 +368,7 @@ class OpenstackBaseHelm(base.BaseHelm):
values['system_overrides'].update({'privatekey': newprivatekey,
'publickey': newpublickey})
self.dbapi.helm_override_update(
name=chart, namespace=namespace, values=values)
app_id=app.id, name=chart, namespace=namespace, values=values)
return newprivatekey, newpublickey

View File

@ -21,11 +21,13 @@ class HelmOverrides(base.SysinvObject):
'namespace': utils.str_or_none,
'user_overrides': utils.str_or_none,
'system_overrides': utils.dict_or_none,
'app_id': int
}
@base.remotable_classmethod
def get_by_name(cls, context, name, namespace):
return cls.dbapi.helm_override_get(name, namespace)
def get_by_appid_name(cls, context, app_id, name, namespace):
return cls.dbapi.helm_override_get(app_id, name, namespace)
def save_changes(self, context, updates):
self.dbapi.helm_override_update(self.name, self.namespace, updates)
self.dbapi.helm_override_update(self.app_id, self.name,
self.namespace, updates)