Add support to preserve app attributes when updating app
Add support to preserve the app attributes from the old version when updating app to a new version. The key "maintain_attributes" in application metadata file indicates if the app attributes will be reused or not during update, user can specify --reuse-attributes <true/false> to override the metadata preference specified by the application. Database column which stores the app attributes is called system_overrides (table helm_overrides), when attributes is mentioned in the code, it means the property stored in column system_overrides in the database. That property is shown to the user as attributes. The naming confusion will be fixed later. Test Plan: PASS: Update app without specify --reuse-attributes PASS: Update app without specify --reuse-attributes app metadata defaults to maintain_attributes=true PASS: Update app specify --reuse-attributes false PASS: Update app specify --reuse-attributes true PASS: Disabled helm chart stays disabled with update Closes-Bug: https://bugs.launchpad.net/starlingx/+bug/1998499 Signed-off-by: Fabricio Henrique Ramos <fabriciohenrique.ramos@windriver.com> Change-Id: I0f9c5c7314deb10f89853c9e5c8e15daf99580ed
This commit is contained in:
parent
39dbec3c18
commit
1e2073bb1a
@ -144,11 +144,16 @@ def do_application_upload(cc, args):
|
||||
help=('Reuse user overrides when updating application'
|
||||
'to a new version. It will supersede the metadata '
|
||||
'preference specified by the application.'))
|
||||
@utils.arg('--reuse-attributes',
|
||||
metavar='<true/false>',
|
||||
help=('Reuse attributes when updating application '
|
||||
'to a new version. It will supersede the metadata '
|
||||
'preference specified by the application.'))
|
||||
def do_application_update(cc, args):
|
||||
"""Update the deployed application to a different version"""
|
||||
data = _application_check(args)
|
||||
|
||||
fields_list = ['reuse_user_overrides']
|
||||
fields_list = ['reuse_user_overrides', 'reuse_attributes']
|
||||
fields = dict((k, v) for (k, v) in vars(args).items()
|
||||
if k in fields_list and not (v is None))
|
||||
data.update(fields)
|
||||
|
@ -436,6 +436,19 @@ class KubeAppController(rest.RestController):
|
||||
"Application-update rejected: "
|
||||
"invalid reuse_user_overrides setting."))
|
||||
|
||||
reuse_attributes_flag = body.get('reuse_attributes', None)
|
||||
if reuse_attributes_flag is None:
|
||||
# None means let the application decide
|
||||
reuse_attributes = None
|
||||
elif reuse_attributes_flag in ['true', 'True']:
|
||||
reuse_attributes = True
|
||||
elif reuse_attributes_flag in ['false', 'False']:
|
||||
reuse_attributes = False
|
||||
else:
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"Application-update rejected: "
|
||||
"invalid reuse_attributes setting."))
|
||||
|
||||
try:
|
||||
applied_app = objects.kube_app.get_by_name(pecan.request.context, name)
|
||||
except exception.KubeAppNotFound:
|
||||
@ -525,7 +538,9 @@ class KubeAppController(rest.RestController):
|
||||
pecan.request.rpcapi.perform_app_update(pecan.request.context,
|
||||
applied_app, target_app,
|
||||
tarfile, operation,
|
||||
lifecycle_hook_info, reuse_overrides)
|
||||
lifecycle_hook_info,
|
||||
reuse_overrides,
|
||||
reuse_attributes)
|
||||
|
||||
return KubeApp.convert_with_links(target_app)
|
||||
|
||||
|
@ -1820,6 +1820,7 @@ HOOK_PARAMETERS_MAP = {
|
||||
}
|
||||
|
||||
# Application metadata constants
|
||||
APP_METADATA_MAINTAIN_ATTRIBUTES = 'maintain_attributes'
|
||||
APP_METADATA_MAINTAIN_USER_OVERRIDES = 'maintain_user_overrides'
|
||||
APP_METADATA_APPLY_PROGRESS_ADJUST = 'apply_progress_adjust'
|
||||
APP_METADATA_APPLY_PROGRESS_ADJUST_DEFAULT_VALUE = 0
|
||||
|
@ -1657,6 +1657,47 @@ class AppOperator(object):
|
||||
"Chart %s from version %s" % (to_app.name, to_app.version,
|
||||
chart.name, from_app.version))
|
||||
|
||||
def _preserve_attributes(self, from_app, to_app):
|
||||
"""
|
||||
In the scenario of updating application to a new version, this
|
||||
method is used to copy the attributes from the old version
|
||||
to the new version.
|
||||
|
||||
:param from_app: application object that application updating from
|
||||
:param to_app: application object that application updating to
|
||||
"""
|
||||
to_db_app = self._dbapi.kube_app_get(to_app.name)
|
||||
from_db_app = self._dbapi.kube_app_get_inactive_by_name_version(
|
||||
from_app.name, version=from_app.version)
|
||||
|
||||
from_app_db_charts = self._dbapi.helm_override_get_all(from_db_app.id)
|
||||
from_app_charts = {}
|
||||
for chart in from_app_db_charts:
|
||||
from_app_charts.setdefault(chart.name, {}).update(
|
||||
{chart.namespace: chart.system_overrides})
|
||||
|
||||
for chart in to_app.charts:
|
||||
if (chart.name in from_app_charts and
|
||||
chart.namespace in from_app_charts[chart.name] and
|
||||
from_app_charts[chart.name][chart.namespace]):
|
||||
system_overrides = {'system_overrides': from_app_charts[chart.name][chart.namespace]}
|
||||
try:
|
||||
self._dbapi.helm_override_update(
|
||||
app_id=to_db_app.id, name=chart.name,
|
||||
namespace=chart.namespace, values=system_overrides)
|
||||
except exception.HelmOverrideNotFound:
|
||||
# Unexpected
|
||||
values = {
|
||||
'name': chart.name,
|
||||
'namespace': chart.namespace,
|
||||
'app_id': to_db_app.id
|
||||
}
|
||||
values.update(system_overrides)
|
||||
self._dbapi.helm_override_create(values=values)
|
||||
LOG.info("Application %s (%s) will apply the attributes for"
|
||||
"Chart %s from version %s" % (to_app.name, to_app.version,
|
||||
chart.name, from_app.version))
|
||||
|
||||
def _make_app_request(self, app, request, overrides_str=None):
|
||||
if app.is_fluxcd_app:
|
||||
return self._make_fluxcd_operation_with_monitor(app, request)
|
||||
@ -3056,7 +3097,8 @@ class AppOperator(object):
|
||||
return False
|
||||
|
||||
def perform_app_update(self, from_rpc_app, to_rpc_app, tarfile,
|
||||
operation, lifecycle_hook_info_app_update, reuse_user_overrides=None):
|
||||
operation, lifecycle_hook_info_app_update, reuse_user_overrides=None,
|
||||
reuse_attributes=None):
|
||||
"""Process application update request
|
||||
|
||||
This method leverages the existing application upload workflow to
|
||||
@ -3084,6 +3126,7 @@ class AppOperator(object):
|
||||
:param operation: apply or rollback
|
||||
:param lifecycle_hook_info_app_update: LifecycleHookInfo object
|
||||
:param reuse_user_overrides: (optional) True or False
|
||||
:param reuse_attributes: (optional) True or False
|
||||
|
||||
"""
|
||||
|
||||
@ -3164,6 +3207,17 @@ class AppOperator(object):
|
||||
if reuse_overrides:
|
||||
self._preserve_user_overrides(from_app, to_app)
|
||||
|
||||
reuse_app_attributes = \
|
||||
self._get_metadata_value(to_app,
|
||||
constants.APP_METADATA_MAINTAIN_ATTRIBUTES,
|
||||
False)
|
||||
if reuse_attributes is not None:
|
||||
reuse_app_attributes = reuse_attributes
|
||||
|
||||
# Preserve attributes for the new app
|
||||
if reuse_app_attributes:
|
||||
self._preserve_attributes(from_app, to_app)
|
||||
|
||||
# The app_apply will generate new versioned overrides for the
|
||||
# app upgrade and will enable the new plugins for that version.
|
||||
|
||||
|
@ -14254,7 +14254,8 @@ class ConductorManager(service.PeriodicService):
|
||||
return app_applied
|
||||
|
||||
def perform_app_update(self, context, from_rpc_app, to_rpc_app, tarfile,
|
||||
operation, lifecycle_hook_info_app_update, reuse_user_overrides=None):
|
||||
operation, lifecycle_hook_info_app_update, reuse_user_overrides=None,
|
||||
reuse_attributes=None):
|
||||
"""Handling of application update request (via AppOperator)
|
||||
|
||||
:param context: request context.
|
||||
@ -14266,12 +14267,14 @@ class ConductorManager(service.PeriodicService):
|
||||
:param operation: apply or rollback
|
||||
:param lifecycle_hook_info_app_update: LifecycleHookInfo object
|
||||
:param reuse_user_overrides: (optional) True or False
|
||||
:param reuse_attributes: (optional) True or False
|
||||
|
||||
"""
|
||||
lifecycle_hook_info_app_update.operation = constants.APP_UPDATE_OP
|
||||
|
||||
self._app.perform_app_update(from_rpc_app, to_rpc_app, tarfile,
|
||||
operation, lifecycle_hook_info_app_update, reuse_user_overrides)
|
||||
operation, lifecycle_hook_info_app_update, reuse_user_overrides,
|
||||
reuse_attributes)
|
||||
|
||||
def perform_app_remove(self, context, rpc_app, lifecycle_hook_info_app_remove, force=False):
|
||||
"""Handling of application removal request (via AppOperator)
|
||||
|
@ -1786,7 +1786,8 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
||||
lifecycle_hook_info_app_apply=lifecycle_hook_info))
|
||||
|
||||
def perform_app_update(self, context, from_rpc_app, to_rpc_app, tarfile,
|
||||
operation, lifecycle_hook_info, reuse_user_overrides=None):
|
||||
operation, lifecycle_hook_info, reuse_user_overrides=None,
|
||||
reuse_attributes=None):
|
||||
"""Handle application update request
|
||||
|
||||
:param context: request context.
|
||||
@ -1799,6 +1800,7 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
||||
:param lifecycle_hook_info: LifecycleHookInfo object
|
||||
|
||||
:param reuse_user_overrides: (optional) True or False
|
||||
:param reuse_attributes: (optional) True or False
|
||||
"""
|
||||
return self.cast(context,
|
||||
self.make_msg('perform_app_update',
|
||||
@ -1807,7 +1809,8 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
||||
tarfile=tarfile,
|
||||
operation=operation,
|
||||
lifecycle_hook_info_app_update=lifecycle_hook_info,
|
||||
reuse_user_overrides=reuse_user_overrides))
|
||||
reuse_user_overrides=reuse_user_overrides,
|
||||
reuse_attributes=reuse_attributes))
|
||||
|
||||
def perform_app_remove(self, context, rpc_app, lifecycle_hook_info, force=False):
|
||||
"""Handle application remove request
|
||||
|
Loading…
Reference in New Issue
Block a user