Add sysinv commands related to helm chart overrides
When dealing with "system" helm charts (like those used for OpenStack) we want to support both system-generated overrides as well as user-specified overrides. There are various ways in helm to specify overrides, so we try to support as many of them as possible here. Because we're not actually upgrading a chart in helm it becomes very difficult to reliably handle the equivalent of helm's "--set-string" operation so for now we won't be able to provide it. Story: 2002876 Task: 22831 Change-Id: I27d7e61b1ae0a849ecf99afbdbbaf7ba3bfcaee2 Signed-off-by: Jack Ding <jack.ding@windriver.com>
This commit is contained in:
parent
9878251239
commit
49041ff8a9
|
@ -30,6 +30,7 @@ from cgtsclient.v1 import event_log
|
||||||
from cgtsclient.v1 import event_suppression
|
from cgtsclient.v1 import event_suppression
|
||||||
from cgtsclient.v1 import firewallrules
|
from cgtsclient.v1 import firewallrules
|
||||||
from cgtsclient.v1 import health
|
from cgtsclient.v1 import health
|
||||||
|
from cgtsclient.v1 import helm
|
||||||
from cgtsclient.v1 import ialarm
|
from cgtsclient.v1 import ialarm
|
||||||
from cgtsclient.v1 import icommunity
|
from cgtsclient.v1 import icommunity
|
||||||
from cgtsclient.v1 import icpu
|
from cgtsclient.v1 import icpu
|
||||||
|
@ -148,3 +149,4 @@ class Client(http.HTTPClient):
|
||||||
self.storage_tier = storage_tier.StorageTierManager(self)
|
self.storage_tier = storage_tier.StorageTierManager(self)
|
||||||
self.storage_ceph_external = \
|
self.storage_ceph_external = \
|
||||||
storage_ceph_external.StorageCephExternalManager(self)
|
storage_ceph_external.StorageCephExternalManager(self)
|
||||||
|
self.helm = helm.HelmManager(self)
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
from cgtsclient.common import base
|
||||||
|
|
||||||
|
|
||||||
|
class Helm(base.Resource):
|
||||||
|
def __repr__(self):
|
||||||
|
return "<helm %s>" % self._info
|
||||||
|
|
||||||
|
|
||||||
|
class HelmManager(base.Manager):
|
||||||
|
resource_class = Helm
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _path(name=''):
|
||||||
|
return '/v1/helm_charts/%s' % name
|
||||||
|
|
||||||
|
def list_charts(self):
|
||||||
|
return self._list(self._path(), 'charts')
|
||||||
|
|
||||||
|
def get_overrides(self, name):
|
||||||
|
"""Get overrides for a given chart.
|
||||||
|
|
||||||
|
:param name: name of the chart
|
||||||
|
|
||||||
|
This will return the end-user, system, and combined overrides for the
|
||||||
|
specified chart.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self._list(self._path(name))[0]
|
||||||
|
except IndexError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def update_overrides(self, name, flag='reset', override_values={}):
|
||||||
|
"""Update overrides for a given chart.
|
||||||
|
|
||||||
|
:param name: name of the chart
|
||||||
|
:param flag: 'reuse' or 'reset' to indicate how to handle existing
|
||||||
|
user overrides for this chart
|
||||||
|
:param override_values: a dict representing the overrides
|
||||||
|
|
||||||
|
This will return the end-user overrides for the specified chart.
|
||||||
|
"""
|
||||||
|
body = {'flag': flag, 'values': override_values}
|
||||||
|
return self._update(self._path(name), body)
|
||||||
|
|
||||||
|
def delete_overrides(self, name):
|
||||||
|
"""Delete overrides for a given chart.
|
||||||
|
|
||||||
|
:param name: name of the chart
|
||||||
|
"""
|
||||||
|
return self._delete(self._path(name))
|
|
@ -0,0 +1,108 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from cgtsclient.common import utils
|
||||||
|
from cgtsclient import exc
|
||||||
|
|
||||||
|
|
||||||
|
def _print_helm_chart(chart):
|
||||||
|
# We only want to print the fields that are in the response, that way
|
||||||
|
# we can reuse this function for printing the override update output
|
||||||
|
# where the system overrides aren't included.
|
||||||
|
ordereddata = OrderedDict(sorted(chart.to_dict().items(),
|
||||||
|
key=lambda t: t[0]))
|
||||||
|
utils.print_dict(ordereddata)
|
||||||
|
|
||||||
|
|
||||||
|
def do_helm_chart_list(cc, args):
|
||||||
|
"""List system helm charts."""
|
||||||
|
charts = cc.helm.list_charts()
|
||||||
|
utils.print_list(charts, ['name'], ['chart name'], sortby=0)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('chart', metavar='<chart name>',
|
||||||
|
help="Name of chart")
|
||||||
|
def do_helm_override_show(cc, args):
|
||||||
|
"""Show overrides for chart."""
|
||||||
|
chart = cc.helm.get_overrides(args.chart)
|
||||||
|
_print_helm_chart(chart)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('chart',
|
||||||
|
metavar='<chart name>',
|
||||||
|
nargs='+',
|
||||||
|
help="Name of chart")
|
||||||
|
def do_helm_override_delete(cc, args):
|
||||||
|
"""Delete overrides for one or more charts."""
|
||||||
|
for chart in args.chart:
|
||||||
|
try:
|
||||||
|
cc.helm.delete_overrides(chart)
|
||||||
|
print 'Deleted chart %s' % chart
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError('chart not found: %s' % chart)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('chart',
|
||||||
|
metavar='<chart name>',
|
||||||
|
help="Name of chart")
|
||||||
|
@utils.arg('--reuse-values', action='store_true', default=False,
|
||||||
|
help='Should we reuse existing helm chart user override values. '
|
||||||
|
'If --reset-values is set this is ignored')
|
||||||
|
@utils.arg('--reset-values', action='store_true', default=False,
|
||||||
|
help='Replace any existing helm chart overrides with the ones '
|
||||||
|
'specified.')
|
||||||
|
@utils.arg('--values', metavar='<file_name>', action='append', dest='files',
|
||||||
|
default=[],
|
||||||
|
help='Specify a YAML file containing helm chart override values. '
|
||||||
|
'Can specify multiple times.')
|
||||||
|
@utils.arg('--set', metavar='<commandline_overrides>', action='append',
|
||||||
|
default=[],
|
||||||
|
help='Set helm chart override values on the command line (can '
|
||||||
|
'specify multiple times or separate values with commas: '
|
||||||
|
'key1=val1,key2=val2). These are processed after "--values" '
|
||||||
|
'files.')
|
||||||
|
def do_helm_override_update(cc, args):
|
||||||
|
"""Update helm chart user overrides."""
|
||||||
|
|
||||||
|
# This logic results in similar behaviour to "helm upgrade".
|
||||||
|
flag = 'reset'
|
||||||
|
if args.reuse_values and not args.reset_values:
|
||||||
|
flag = 'reuse'
|
||||||
|
|
||||||
|
# Overrides can be specified three different ways. To preserve helm's
|
||||||
|
# behaviour we will process all "--values" files first, then all "--set"
|
||||||
|
# values, then finally all "--set-string" values.
|
||||||
|
|
||||||
|
override_files = []
|
||||||
|
# need to handle missing files
|
||||||
|
if args.files:
|
||||||
|
try:
|
||||||
|
for filename in args.files:
|
||||||
|
with open(filename, 'r') as input_file:
|
||||||
|
overrides = yaml.load(input_file)
|
||||||
|
override_files.append(yaml.dump(overrides))
|
||||||
|
except IOError as ex:
|
||||||
|
raise exc.CommandError('error opening values file: %s' % ex)
|
||||||
|
|
||||||
|
override_set = []
|
||||||
|
for override in args.set:
|
||||||
|
override_set.append(override)
|
||||||
|
|
||||||
|
overrides = {
|
||||||
|
'files': override_files,
|
||||||
|
'set': override_set,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
chart = cc.helm.update_overrides(args.chart, flag, overrides)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
raise exc.CommandError('helm chart not found: %s' % args.chart)
|
||||||
|
_print_helm_chart(chart)
|
|
@ -18,6 +18,7 @@ from cgtsclient.v1 import event_log_shell
|
||||||
from cgtsclient.v1 import event_suppression_shell
|
from cgtsclient.v1 import event_suppression_shell
|
||||||
from cgtsclient.v1 import firewallrules_shell
|
from cgtsclient.v1 import firewallrules_shell
|
||||||
from cgtsclient.v1 import health_shell
|
from cgtsclient.v1 import health_shell
|
||||||
|
from cgtsclient.v1 import helm_shell
|
||||||
|
|
||||||
from cgtsclient.v1 import ialarm_shell
|
from cgtsclient.v1 import ialarm_shell
|
||||||
from cgtsclient.v1 import icommunity_shell
|
from cgtsclient.v1 import icommunity_shell
|
||||||
|
@ -111,6 +112,7 @@ COMMAND_MODULES = [
|
||||||
license_shell,
|
license_shell,
|
||||||
certificate_shell,
|
certificate_shell,
|
||||||
storage_tier_shell,
|
storage_tier_shell,
|
||||||
|
helm_shell,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ from sysinv.api.controllers.v1 import event_log
|
||||||
from sysinv.api.controllers.v1 import event_suppression
|
from sysinv.api.controllers.v1 import event_suppression
|
||||||
from sysinv.api.controllers.v1 import firewallrules
|
from sysinv.api.controllers.v1 import firewallrules
|
||||||
from sysinv.api.controllers.v1 import health
|
from sysinv.api.controllers.v1 import health
|
||||||
|
from sysinv.api.controllers.v1 import helm_charts
|
||||||
from sysinv.api.controllers.v1 import host
|
from sysinv.api.controllers.v1 import host
|
||||||
from sysinv.api.controllers.v1 import interface
|
from sysinv.api.controllers.v1 import interface
|
||||||
from sysinv.api.controllers.v1 import link
|
from sysinv.api.controllers.v1 import link
|
||||||
|
@ -109,6 +110,9 @@ class V1(base.APIBase):
|
||||||
ihosts = [link.Link]
|
ihosts = [link.Link]
|
||||||
"Links to the ihosts resource"
|
"Links to the ihosts resource"
|
||||||
|
|
||||||
|
helm_charts = [link.Link]
|
||||||
|
"Links to the helm resource"
|
||||||
|
|
||||||
inode = [link.Link]
|
inode = [link.Link]
|
||||||
"Links to the inode resource"
|
"Links to the inode resource"
|
||||||
|
|
||||||
|
@ -260,6 +264,14 @@ class V1(base.APIBase):
|
||||||
bookmark=True)
|
bookmark=True)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
v1.helm_charts = [link.Link.make_link('self', pecan.request.host_url,
|
||||||
|
'helm_charts', ''),
|
||||||
|
link.Link.make_link('bookmark',
|
||||||
|
pecan.request.host_url,
|
||||||
|
'helm_charts', '',
|
||||||
|
bookmark=True)
|
||||||
|
]
|
||||||
|
|
||||||
v1.inode = [link.Link.make_link('self', pecan.request.host_url,
|
v1.inode = [link.Link.make_link('self', pecan.request.host_url,
|
||||||
'inode', ''),
|
'inode', ''),
|
||||||
link.Link.make_link('bookmark',
|
link.Link.make_link('bookmark',
|
||||||
|
@ -722,6 +734,7 @@ class Controller(rest.RestController):
|
||||||
|
|
||||||
isystems = system.SystemController()
|
isystems = system.SystemController()
|
||||||
ihosts = host.HostController()
|
ihosts = host.HostController()
|
||||||
|
helm_charts = helm_charts.HelmChartsController()
|
||||||
inodes = node.NodeController()
|
inodes = node.NodeController()
|
||||||
icpus = cpu.CPUController()
|
icpus = cpu.CPUController()
|
||||||
imemorys = memory.MemoryController()
|
imemorys = memory.MemoryController()
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pecan
|
||||||
|
from pecan import rest
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import wsme
|
||||||
|
from wsme import types as wtypes
|
||||||
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
|
from sysinv import objects
|
||||||
|
from sysinv.common import exception
|
||||||
|
from sysinv.openstack.common import log
|
||||||
|
from sysinv.openstack.common.gettextutils import _
|
||||||
|
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
SYSTEM_CHARTS = ['mariadb', 'rabbitmq', 'ingress']
|
||||||
|
|
||||||
|
|
||||||
|
class HelmChartsController(rest.RestController):
|
||||||
|
|
||||||
|
@wsme_pecan.wsexpose(wtypes.text)
|
||||||
|
def get_all(self):
|
||||||
|
"""Provides information about the available charts to override."""
|
||||||
|
charts = [{'name': chart} for chart in SYSTEM_CHARTS]
|
||||||
|
return {'charts': charts}
|
||||||
|
|
||||||
|
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
|
||||||
|
def get_one(self, name):
|
||||||
|
"""Retrieve information about the given event_log.
|
||||||
|
|
||||||
|
:param name: name of helm chart
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
db_chart = objects.helm_overrides.get_by_name(
|
||||||
|
pecan.request.context, name)
|
||||||
|
overrides = db_chart.user_overrides
|
||||||
|
except exception.HelmOverrideNotFound:
|
||||||
|
if name in SYSTEM_CHARTS:
|
||||||
|
overrides = {}
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
rpc_chart = {'name': name,
|
||||||
|
'system_overrides': {},
|
||||||
|
'user_overrides': overrides}
|
||||||
|
|
||||||
|
return rpc_chart
|
||||||
|
|
||||||
|
@wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text, wtypes.text)
|
||||||
|
def patch(self, name, flag, values):
|
||||||
|
""" Update user overrides.
|
||||||
|
|
||||||
|
:param name: chart name
|
||||||
|
:param flag: one of "reuse" or "reset", describes how to handle
|
||||||
|
previous user overrides
|
||||||
|
:param values: a dict of different types of user override values
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
db_chart = objects.helm_overrides.get_by_name(
|
||||||
|
pecan.request.context, name)
|
||||||
|
db_values = db_chart.user_overrides
|
||||||
|
except exception.HelmOverrideNotFound:
|
||||||
|
if name in SYSTEM_CHARTS:
|
||||||
|
pecan.request.dbapi.helm_override_create({
|
||||||
|
'name': name,
|
||||||
|
'user_overrides': ''})
|
||||||
|
db_chart = objects.helm_overrides.get_by_name(
|
||||||
|
pecan.request.context, name)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
db_values = db_chart.user_overrides
|
||||||
|
|
||||||
|
# At this point we have potentially two separate types of overrides
|
||||||
|
# specified by the user, values from files and values passed in via
|
||||||
|
# --set . We need to ensure that we call helm using the same
|
||||||
|
# mechanisms to ensure the same behaviour.
|
||||||
|
cmd = ['helm', 'install', '--dry-run', '--debug']
|
||||||
|
|
||||||
|
if flag == 'reuse':
|
||||||
|
values['files'].insert(0, db_values)
|
||||||
|
elif flag == 'reset':
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise wsme.exc.ClientSideError(_("Invalid flag: %s must be either "
|
||||||
|
"'reuse' or 'reset'.") % flag)
|
||||||
|
|
||||||
|
# Now process the newly-passed-in override values
|
||||||
|
tmpfiles = []
|
||||||
|
for value_file in values['files']:
|
||||||
|
# For values passed in from files, write them back out to
|
||||||
|
# temporary files.
|
||||||
|
tmpfile = tempfile.NamedTemporaryFile(delete=False)
|
||||||
|
tmpfile.write(value_file)
|
||||||
|
tmpfile.close()
|
||||||
|
tmpfiles.append(tmpfile.name)
|
||||||
|
cmd.extend(['--values', tmpfile.name])
|
||||||
|
|
||||||
|
for value_set in values['set']:
|
||||||
|
cmd.extend(['--set', value_set])
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
env['KUBECONFIG'] = '/etc/kubernetes/admin.conf'
|
||||||
|
|
||||||
|
# Make a temporary directory with a fake chart in it
|
||||||
|
try:
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
chartfile = tmpdir + '/Chart.yaml'
|
||||||
|
with open(chartfile, 'w') as tmpchart:
|
||||||
|
tmpchart.write('name: mychart\napiVersion: v1\n'
|
||||||
|
'version: 0.1.0\n')
|
||||||
|
cmd.append(tmpdir)
|
||||||
|
|
||||||
|
# Apply changes by calling out to helm to do values merge
|
||||||
|
# using a dummy chart.
|
||||||
|
# NOTE: this requires running sysinv-api as root, will fix it
|
||||||
|
# to use RPC in a followup patch.
|
||||||
|
output = subprocess.check_output(cmd, env=env)
|
||||||
|
|
||||||
|
# Check output for failure
|
||||||
|
|
||||||
|
# Extract the info we want.
|
||||||
|
values = output.split('USER-SUPPLIED VALUES:\n')[1].split(
|
||||||
|
'\nCOMPUTED VALUES:')[0]
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
os.remove(chartfile)
|
||||||
|
os.rmdir(tmpdir)
|
||||||
|
|
||||||
|
for tmpfile in tmpfiles:
|
||||||
|
os.remove(tmpfile)
|
||||||
|
|
||||||
|
# save chart overrides back to DB
|
||||||
|
db_chart.user_overrides = values
|
||||||
|
db_chart.save()
|
||||||
|
|
||||||
|
chart = {'name': name, 'user_overrides': values}
|
||||||
|
|
||||||
|
return chart
|
||||||
|
|
||||||
|
@wsme_pecan.wsexpose(None, unicode, status_code=204)
|
||||||
|
def delete(self, name):
|
||||||
|
"""Delete user overrides for a chart
|
||||||
|
|
||||||
|
:param name: chart name.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
pecan.request.dbapi.helm_override_destroy(name)
|
||||||
|
except exception.HelmOverrideNotFound:
|
||||||
|
pass
|
|
@ -578,6 +578,10 @@ class CertificateAlreadyExists(Conflict):
|
||||||
message = _("A Certificate with uuid %(uuid)s already exists.")
|
message = _("A Certificate with uuid %(uuid)s already exists.")
|
||||||
|
|
||||||
|
|
||||||
|
class HelmOverrideAlreadyExists(Conflict):
|
||||||
|
message = _("A HelmOverride with name %(name)s already exists.")
|
||||||
|
|
||||||
|
|
||||||
class InstanceDeployFailure(Invalid):
|
class InstanceDeployFailure(Invalid):
|
||||||
message = _("Failed to deploy instance: %(reason)s")
|
message = _("Failed to deploy instance: %(reason)s")
|
||||||
|
|
||||||
|
@ -887,6 +891,10 @@ class CertificateNotFound(NotFound):
|
||||||
message = _("No certificate with uuid %(uuid)s")
|
message = _("No certificate with uuid %(uuid)s")
|
||||||
|
|
||||||
|
|
||||||
|
class HelmOverrideNotFound(NotFound):
|
||||||
|
message = _("No helm override with name %(name)s")
|
||||||
|
|
||||||
|
|
||||||
class CertificateTypeNotFound(NotFound):
|
class CertificateTypeNotFound(NotFound):
|
||||||
message = _("No certificate type of %(certtype)s")
|
message = _("No certificate type of %(certtype)s")
|
||||||
|
|
||||||
|
|
|
@ -7436,3 +7436,53 @@ class Connection(api.Connection):
|
||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
raise exception.CertificateNotFound(uuid)
|
raise exception.CertificateNotFound(uuid)
|
||||||
query.delete()
|
query.delete()
|
||||||
|
|
||||||
|
def _helm_override_get(self, name):
|
||||||
|
query = model_query(models.HelmOverrides)
|
||||||
|
query = query.filter_by(name=name)
|
||||||
|
try:
|
||||||
|
return query.one()
|
||||||
|
except NoResultFound:
|
||||||
|
raise exception.HelmOverrideNotFound(name)
|
||||||
|
|
||||||
|
@objects.objectify(objects.helm_overrides)
|
||||||
|
def helm_override_create(self, values):
|
||||||
|
|
||||||
|
overrides = models.HelmOverrides()
|
||||||
|
overrides.update(values)
|
||||||
|
with _session_for_write() as session:
|
||||||
|
try:
|
||||||
|
session.add(overrides)
|
||||||
|
session.flush()
|
||||||
|
except db_exc.DBDuplicateEntry:
|
||||||
|
LOG.error("Failed to add HelmOverrides %s. "
|
||||||
|
"Already exists with this name" %
|
||||||
|
(values['name']))
|
||||||
|
raise exception.HelmOverrideAlreadyExists(name=values['name'])
|
||||||
|
return self._helm_override_get(values['name'])
|
||||||
|
|
||||||
|
@objects.objectify(objects.helm_overrides)
|
||||||
|
def helm_override_get(self, name):
|
||||||
|
return self._helm_override_get(name)
|
||||||
|
|
||||||
|
@objects.objectify(objects.helm_overrides)
|
||||||
|
def helm_override_update(self, name, values):
|
||||||
|
with _session_for_write() as session:
|
||||||
|
query = model_query(models.HelmOverrides, session=session)
|
||||||
|
query = query.filter_by(name=name)
|
||||||
|
|
||||||
|
count = query.update(values, synchronize_session='fetch')
|
||||||
|
if count == 0:
|
||||||
|
raise exception.HelmOverrideNotFound(name)
|
||||||
|
return query.one()
|
||||||
|
|
||||||
|
def helm_override_destroy(self, name):
|
||||||
|
with _session_for_write() as session:
|
||||||
|
query = model_query(models.HelmOverrides, session=session)
|
||||||
|
query = query.filter_by(name=name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
query.one()
|
||||||
|
except NoResultFound:
|
||||||
|
raise exception.HelmOverrideNotFound(name)
|
||||||
|
query.delete()
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from sqlalchemy import DateTime, String, Text
|
||||||
|
from sqlalchemy import Column, MetaData, Table
|
||||||
|
|
||||||
|
from sysinv.openstack.common import log
|
||||||
|
|
||||||
|
ENGINE = 'InnoDB'
|
||||||
|
CHARSET = 'utf8'
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
"""
|
||||||
|
This database upgrade creates a new table for storing helm chart
|
||||||
|
user-specified override values.
|
||||||
|
"""
|
||||||
|
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
# Define and create the helm_overrides table.
|
||||||
|
helm_overrides = Table(
|
||||||
|
'helm_overrides',
|
||||||
|
meta,
|
||||||
|
Column('created_at', DateTime),
|
||||||
|
Column('updated_at', DateTime),
|
||||||
|
Column('deleted_at', DateTime),
|
||||||
|
Column('name', String(255), unique=True, index=True),
|
||||||
|
Column('user_overrides', Text, nullable=True),
|
||||||
|
|
||||||
|
mysql_engine=ENGINE,
|
||||||
|
mysql_charset=CHARSET,
|
||||||
|
)
|
||||||
|
|
||||||
|
helm_overrides.create()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migrate_engine):
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
# As per other openstack components, downgrade is
|
||||||
|
# unsupported in this release.
|
||||||
|
raise NotImplementedError('SysInv database downgrade is unsupported.')
|
|
@ -1635,3 +1635,10 @@ class certificate(Base):
|
||||||
start_date = Column(DateTime(timezone=False))
|
start_date = Column(DateTime(timezone=False))
|
||||||
expiry_date = Column(DateTime(timezone=False))
|
expiry_date = Column(DateTime(timezone=False))
|
||||||
capabilities = Column(JSONEncodedDict)
|
capabilities = Column(JSONEncodedDict)
|
||||||
|
|
||||||
|
|
||||||
|
class HelmOverrides(Base):
|
||||||
|
__tablename__ = 'helm_overrides'
|
||||||
|
|
||||||
|
name = Column(String(255), primary_key=True, unique=True)
|
||||||
|
user_overrides = Column(Text, nullable=True)
|
||||||
|
|
|
@ -36,6 +36,7 @@ from sysinv.objects import drbdconfig
|
||||||
from sysinv.objects import port_ethernet
|
from sysinv.objects import port_ethernet
|
||||||
from sysinv.objects import event_log
|
from sysinv.objects import event_log
|
||||||
from sysinv.objects import event_suppression
|
from sysinv.objects import event_suppression
|
||||||
|
from sysinv.objects import helm_overrides
|
||||||
from sysinv.objects import host
|
from sysinv.objects import host
|
||||||
from sysinv.objects import host_upgrade
|
from sysinv.objects import host_upgrade
|
||||||
from sysinv.objects import network_infra
|
from sysinv.objects import network_infra
|
||||||
|
@ -179,6 +180,7 @@ storage_file = storage_file.StorageFile
|
||||||
storage_external = storage_external.StorageExternal
|
storage_external = storage_external.StorageExternal
|
||||||
storage_tier = storage_tier.StorageTier
|
storage_tier = storage_tier.StorageTier
|
||||||
storage_ceph_external = storage_ceph_external.StorageCephExternal
|
storage_ceph_external = storage_ceph_external.StorageCephExternal
|
||||||
|
helm_overrides = helm_overrides.HelmOverrides
|
||||||
|
|
||||||
__all__ = (system,
|
__all__ = (system,
|
||||||
cluster,
|
cluster,
|
||||||
|
@ -245,6 +247,7 @@ __all__ = (system,
|
||||||
storage_external,
|
storage_external,
|
||||||
storage_tier,
|
storage_tier,
|
||||||
storage_ceph_external,
|
storage_ceph_external,
|
||||||
|
helm_overrides,
|
||||||
# alias objects for RPC compatibility
|
# alias objects for RPC compatibility
|
||||||
ihost,
|
ihost,
|
||||||
ilvg,
|
ilvg,
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
# coding=utf-8
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from sysinv.db import api as db_api
|
||||||
|
from sysinv.objects import base
|
||||||
|
from sysinv.objects import utils
|
||||||
|
|
||||||
|
|
||||||
|
class HelmOverrides(base.SysinvObject):
|
||||||
|
# VERSION 1.0: Initial version
|
||||||
|
VERSION = '1.0'
|
||||||
|
|
||||||
|
dbapi = db_api.get_instance()
|
||||||
|
|
||||||
|
fields = {'name': utils.str_or_none,
|
||||||
|
'user_overrides': utils.str_or_none,
|
||||||
|
}
|
||||||
|
|
||||||
|
@base.remotable_classmethod
|
||||||
|
def get_by_name(cls, context, name):
|
||||||
|
return cls.dbapi.helm_override_get(name)
|
||||||
|
|
||||||
|
def save_changes(self, context, updates):
|
||||||
|
self.dbapi.helm_override_update(self.name, updates)
|
Loading…
Reference in New Issue