Adding upgrade strategy commands

dcmanager strategy-config
dcmanager upgrade-strategy

This change refactors the existing sw-update code so that
patch and upgrades share common functionality.

This adds the strategy 'type' to the CLI output so that a
user can differentiate between which strategy type is
being orchestrated.

patch-strategy-config is generic to all update types, so a new
strategy-config CLI command is now registered.

Change-Id: Icd33eb26f907e8e250ebddbba7d2cebea3592ac7
Depends-On: https://review.opendev.org/#/c/721620
Story: 2007403
Task: 39654
Signed-off-by: albailey <Al.Bailey@windriver.com>
This commit is contained in:
albailey 2020-04-14 15:00:01 -05:00
parent 19f027179c
commit c640a51440
12 changed files with 592 additions and 206 deletions

View File

@ -20,23 +20,22 @@
# of this software may be licensed only pursuant to the terms # of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement. # of an applicable Wind River license agreement.
# #
import six
import keystoneauth1.identity.generic as auth_plugin import keystoneauth1.identity.generic as auth_plugin
from keystoneauth1 import session as ks_session from keystoneauth1 import session as ks_session
import osprofiler.profiler
from dcmanagerclient.api import httpclient from dcmanagerclient.api import httpclient
from dcmanagerclient.api.v1 import alarm_manager as am from dcmanagerclient.api.v1 import alarm_manager as am
from dcmanagerclient.api.v1 import fw_update_manager as fum
from dcmanagerclient.api.v1 import strategy_step_manager as ssm
from dcmanagerclient.api.v1 import subcloud_deploy_manager as sdm from dcmanagerclient.api.v1 import subcloud_deploy_manager as sdm
from dcmanagerclient.api.v1 import subcloud_group_manager as gm from dcmanagerclient.api.v1 import subcloud_group_manager as gm
from dcmanagerclient.api.v1 import subcloud_manager as sm from dcmanagerclient.api.v1 import subcloud_manager as sm
from dcmanagerclient.api.v1 import sw_update_manager as sum from dcmanagerclient.api.v1 import sw_patch_manager as spm
from dcmanagerclient.api.v1 import sw_update_options_manager as suom from dcmanagerclient.api.v1 import sw_update_options_manager as suom
from dcmanagerclient.api.v1 import sw_upgrade_manager as supm
import osprofiler.profiler
import six
_DEFAULT_DCMANAGER_URL = "http://localhost:8119/v1.0" _DEFAULT_DCMANAGER_URL = "http://localhost:8119/v1.0"
@ -102,11 +101,13 @@ class Client(object):
self.subcloud_deploy_manager = sdm.subcloud_deploy_manager( self.subcloud_deploy_manager = sdm.subcloud_deploy_manager(
self.http_client) self.http_client)
self.alarm_manager = am.alarm_manager(self.http_client) self.alarm_manager = am.alarm_manager(self.http_client)
self.sw_update_manager = sum.sw_update_manager(self.http_client) self.fw_update_manager = fum.fw_update_manager(self.http_client)
self.sw_patch_manager = spm.sw_patch_manager(self.http_client)
self.sw_update_options_manager = \ self.sw_update_options_manager = \
suom.sw_update_options_manager(self.http_client) suom.sw_update_options_manager(self.http_client)
self.strategy_step_manager = sum.strategy_step_manager( self.sw_upgrade_manager = supm.sw_upgrade_manager(self.http_client)
self.http_client) self.strategy_step_manager = \
ssm.strategy_step_manager(self.http_client)
def authenticate(dcmanager_url=None, username=None, def authenticate(dcmanager_url=None, username=None,

View File

@ -0,0 +1,32 @@
# Copyright (c) 2017 Ericsson AB.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
from dcmanagerclient.api.v1.sw_update_manager import sw_update_manager
SW_UPDATE_TYPE_FIRMWARE = 'firmware'
class fw_update_manager(sw_update_manager):
def __init__(self, http_client):
super(fw_update_manager, self).__init__(
http_client,
update_type=SW_UPDATE_TYPE_FIRMWARE)

View File

@ -0,0 +1,87 @@
# Copyright (c) 2017 Ericsson AB.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2017-2020 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
from dcmanagerclient.api import base
from dcmanagerclient.api.base import get_json
class StrategyStep(base.Resource):
resource_name = 'strategy_step'
def __init__(self, manager, cloud, stage, state, details,
started_at, finished_at, created_at, updated_at):
self.manager = manager
self.cloud = cloud
self.stage = stage
self.state = state
self.details = details
self.started_at = started_at
self.finished_at = finished_at
self.created_at = created_at
self.updated_at = updated_at
class strategy_step_manager(base.ResourceManager):
def __init__(self, http_client):
super(strategy_step_manager, self).__init__(http_client)
self.resource_class = StrategyStep
self.steps_url = '/sw-update-strategy/steps'
self.response_key = 'strategy-steps'
def list_strategy_steps(self):
return self._strategy_step_list(self.steps_url)
def strategy_step_detail(self, cloud_name):
url = '{}/{}'.format(self.steps_url, cloud_name)
return self._strategy_step_detail(url)
def build_from_json(self, json_object):
return self.resource_class(
self,
cloud=json_object['cloud'],
stage=json_object['stage'],
state=json_object['state'],
details=json_object['details'],
started_at=json_object['started-at'],
finished_at=json_object['finished-at'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at'])
def _strategy_step_list(self, url):
resp = self.http_client.get(url)
if resp.status_code != 200:
self._raise_api_exception(resp)
json_response_key = get_json(resp)
json_objects = json_response_key[self.response_key]
resource = []
for json_object in json_objects:
resource.append(self.build_from_json(json_object))
return resource
def _strategy_step_detail(self, url):
resp = self.http_client.get(url)
if resp.status_code != 200:
self._raise_api_exception(resp)
json_object = get_json(resp)
resource = list()
resource.append(self.build_from_json(json_object))
return resource

View File

@ -0,0 +1,31 @@
# Copyright (c) 2017 Ericsson AB.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2017 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
from dcmanagerclient.api.v1.sw_update_manager import sw_update_manager
SW_UPDATE_TYPE_PATCH = 'patch'
class sw_patch_manager(sw_update_manager):
def __init__(self, http_client):
super(sw_patch_manager, self).__init__(
http_client,
update_type=SW_UPDATE_TYPE_PATCH)

View File

@ -26,13 +26,21 @@ from dcmanagerclient.api import base
from dcmanagerclient.api.base import get_json from dcmanagerclient.api.base import get_json
# todo(abailey): Update SwUpdateStrategy based on 'subcloud group'
class SwUpdateStrategy(base.Resource): class SwUpdateStrategy(base.Resource):
resource_name = 'sw_update_strategy' resource_name = 'sw_update_strategy'
def __init__(self, manager, subcloud_apply_type, max_parallel_subclouds, def __init__(self,
stop_on_failure, state, manager,
created_at, updated_at): strategy_type,
subcloud_apply_type,
max_parallel_subclouds,
stop_on_failure,
state,
created_at,
updated_at):
self.manager = manager self.manager = manager
self.strategy_type = strategy_type
self.subcloud_apply_type = subcloud_apply_type self.subcloud_apply_type = subcloud_apply_type
self.max_parallel_subclouds = max_parallel_subclouds self.max_parallel_subclouds = max_parallel_subclouds
self.stop_on_failure = stop_on_failure self.stop_on_failure = stop_on_failure
@ -41,169 +49,94 @@ class SwUpdateStrategy(base.Resource):
self.updated_at = updated_at self.updated_at = updated_at
class StrategyStep(base.Resource):
resource_name = 'strategy_step'
def __init__(self, manager, cloud, stage, state, details,
started_at, finished_at, created_at, updated_at):
self.manager = manager
self.cloud = cloud
self.stage = stage
self.state = state
self.details = details
self.started_at = started_at
self.finished_at = finished_at
self.created_at = created_at
self.updated_at = updated_at
class sw_update_manager(base.ResourceManager): class sw_update_manager(base.ResourceManager):
resource_class = SwUpdateStrategy """sw_update_managea
def create_patch_strategy(self, **kwargs): sw_update_manager is an abstract class that is used by subclasses to
manage API actions for specific update strategy types such as software
patches and firmware updates.
"""
def __init__(self, http_client,
update_type,
resource_class=SwUpdateStrategy,
url='sw-update-strategy'):
super(sw_update_manager, self).__init__(http_client)
self.resource_class = resource_class
self.update_type = update_type
# create_url is typically /<foo>/
self.create_url = '/{}/'.format(url)
# get_url is typically /<foo>
self.get_url = '/{}'.format(url)
# delete_url is typically /<foo> (same as get)
self.delete_url = '/{}'.format(url)
# actions_url is typically /<foo>/actions
self.actions_url = '/{}/actions'.format(url)
def create_sw_update_strategy(self, **kwargs):
data = kwargs data = kwargs
data.update({'type': 'patch'}) data.update({'type': self.update_type})
url = '/sw-update-strategy/' return self._sw_update_create(self.create_url, data)
return self.sw_update_create(url, data)
def patch_strategy_detail(self): def update_sw_strategy_detail(self):
url = '/sw-update-strategy' return self._sw_update_detail(self.get_url)
return self.sw_update_detail(url)
def delete_patch_strategy(self): def delete_sw_update_strategy(self):
url = '/sw-update-strategy' return self._sw_update_delete(self.delete_url)
return self.sw_update_delete(url)
def apply_patch_strategy(self): def apply_sw_update_strategy(self):
data = {'action': 'apply'} data = {'action': 'apply'}
url = '/sw-update-strategy/actions' return self._sw_update_action(self.actions_url, data)
return self.sw_update_action(url, data)
def abort_patch_strategy(self): def abort_sw_update_strategy(self):
data = {'action': 'abort'} data = {'action': 'abort'}
url = '/sw-update-strategy/actions' return self._sw_update_action(self.actions_url, data)
return self.sw_update_action(url, data)
def sw_update_create(self, url, data): def _build_from_json(self, json_object):
return self.resource_class(
self,
strategy_type=json_object['type'],
subcloud_apply_type=json_object['subcloud-apply-type'],
max_parallel_subclouds=json_object['max-parallel-subclouds'],
stop_on_failure=json_object['stop-on-failure'],
state=json_object['state'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at'])
def _sw_update_create(self, url, data):
data = json.dumps(data) data = json.dumps(data)
resp = self.http_client.post(url, data) resp = self.http_client.post(url, data)
if resp.status_code != 200: if resp.status_code != 200:
self._raise_api_exception(resp) self._raise_api_exception(resp)
json_object = get_json(resp) json_object = get_json(resp)
resource = list() resource = list()
resource.append( resource.append(self._build_from_json(json_object))
self.resource_class(
self,
subcloud_apply_type=json_object['subcloud-apply-type'],
max_parallel_subclouds=json_object['max-parallel-subclouds'],
stop_on_failure=json_object['stop-on-failure'],
state=json_object['state'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at']))
return resource return resource
def sw_update_delete(self, url): def _sw_update_delete(self, url):
resp = self.http_client.delete(url) resp = self.http_client.delete(url)
if resp.status_code != 200: if resp.status_code != 200:
self._raise_api_exception(resp) self._raise_api_exception(resp)
json_object = get_json(resp) json_object = get_json(resp)
resource = list() resource = list()
resource.append( resource.append(self._build_from_json(json_object))
self.resource_class(
self,
subcloud_apply_type=json_object['subcloud-apply-type'],
max_parallel_subclouds=json_object['max-parallel-subclouds'],
stop_on_failure=json_object['stop-on-failure'],
state=json_object['state'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at']))
return resource return resource
def sw_update_detail(self, url): def _sw_update_detail(self, url):
resp = self.http_client.get(url) resp = self.http_client.get(url)
if resp.status_code != 200: if resp.status_code != 200:
self._raise_api_exception(resp) self._raise_api_exception(resp)
json_object = get_json(resp) json_object = get_json(resp)
resource = list() resource = list()
resource.append( resource.append(self._build_from_json(json_object))
self.resource_class(
self,
subcloud_apply_type=json_object['subcloud-apply-type'],
max_parallel_subclouds=json_object['max-parallel-subclouds'],
stop_on_failure=json_object['stop-on-failure'],
state=json_object['state'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at']))
return resource return resource
def sw_update_action(self, url, data): def _sw_update_action(self, url, data):
data = json.dumps(data) data = json.dumps(data)
resp = self.http_client.post(url, data) resp = self.http_client.post(url, data)
if resp.status_code != 200: if resp.status_code != 200:
self._raise_api_exception(resp) self._raise_api_exception(resp)
json_object = get_json(resp) json_object = get_json(resp)
resource = list() resource = list()
resource.append( resource.append(self._build_from_json(json_object))
self.resource_class(
self,
subcloud_apply_type=json_object['subcloud-apply-type'],
max_parallel_subclouds=json_object['max-parallel-subclouds'],
stop_on_failure=json_object['stop-on-failure'],
state=json_object['state'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at']))
return resource
class strategy_step_manager(base.ResourceManager):
resource_class = StrategyStep
def list_strategy_steps(self):
url = '/sw-update-strategy/steps'
return self.strategy_step_list(url)
def strategy_step_detail(self, cloud_name):
url = '/sw-update-strategy/steps/%s' % cloud_name
return self._strategy_step_detail(url)
def strategy_step_list(self, url):
resp = self.http_client.get(url)
if resp.status_code != 200:
self._raise_api_exception(resp)
json_response_key = get_json(resp)
json_objects = json_response_key['strategy-steps']
resource = []
for json_object in json_objects:
resource.append(
self.resource_class(
self,
cloud=json_object['cloud'],
stage=json_object['stage'],
state=json_object['state'],
details=json_object['details'],
started_at=json_object['started-at'],
finished_at=json_object['finished-at'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at'],
))
return resource
def _strategy_step_detail(self, url):
resp = self.http_client.get(url)
if resp.status_code != 200:
self._raise_api_exception(resp)
json_object = get_json(resp)
resource = list()
resource.append(
self.resource_class(
self,
cloud=json_object['cloud'],
stage=json_object['stage'],
state=json_object['state'],
details=json_object['details'],
started_at=json_object['started-at'],
finished_at=json_object['finished-at'],
created_at=json_object['created-at'],
updated_at=json_object['updated-at'],
))
return resource return resource

View File

@ -0,0 +1,32 @@
# Copyright (c) 2017 Ericsson AB.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
from dcmanagerclient.api.v1.sw_update_manager import sw_update_manager
SW_UPDATE_TYPE_UPGRADE = 'upgrade'
class sw_upgrade_manager(sw_update_manager):
def __init__(self, http_client):
super(sw_upgrade_manager, self).__init__(
http_client,
update_type=SW_UPDATE_TYPE_UPGRADE)

View File

@ -0,0 +1,59 @@
# Copyright (c) 2017 Ericsson AB.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
from dcmanagerclient.commands.v1 import sw_update_manager
class FwUpdateManagerMixin(object):
"""This Mixin provides the update manager used for firmware updates."""
def get_sw_update_manager(self):
dcmanager_client = self.app.client_manager.fw_update_manager
return dcmanager_client.fw_update_manager
class CreateFwUpdateStrategy(FwUpdateManagerMixin,
sw_update_manager.CreateSwUpdateStrategy):
"""Create a firmware update strategy."""
pass
class ShowFwUpdateStrategy(FwUpdateManagerMixin,
sw_update_manager.ShowSwUpdateStrategy):
"""Show the details of a firmware update strategy for a subcloud."""
pass
class DeleteFwUpdateStrategy(FwUpdateManagerMixin,
sw_update_manager.DeleteSwUpdateStrategy):
"""Delete firmware update strategy from the database."""
pass
class ApplyFwUpdateStrategy(FwUpdateManagerMixin,
sw_update_manager.ApplySwUpdateStrategy):
"""Apply a firmware update strategy."""
pass
class AbortFwUpdateStrategy(FwUpdateManagerMixin,
sw_update_manager.AbortSwUpdateStrategy):
"""Abort a firmware update strategy."""
pass

View File

@ -0,0 +1,59 @@
# Copyright (c) 2017 Ericsson AB.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2017-2020 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
from dcmanagerclient.commands.v1 import sw_update_manager
class SwPatchManagerMixin(object):
"""This Mixin provides the update manager used for sw patch."""
def get_sw_update_manager(self):
dcmanager_client = self.app.client_manager.sw_patch_manager
return dcmanager_client.sw_patch_manager
class CreatePatchUpdateStrategy(SwPatchManagerMixin,
sw_update_manager.CreateSwUpdateStrategy):
"""Create a patch update strategy."""
pass
class ShowPatchUpdateStrategy(SwPatchManagerMixin,
sw_update_manager.ShowSwUpdateStrategy):
"""Show the details of a patch update strategy for a subcloud."""
pass
class DeletePatchUpdateStrategy(SwPatchManagerMixin,
sw_update_manager.DeleteSwUpdateStrategy):
"""Delete patch update strategy from the database."""
pass
class ApplyPatchUpdateStrategy(SwPatchManagerMixin,
sw_update_manager.ApplySwUpdateStrategy):
"""Apply a patch update strategy."""
pass
class AbortPatchUpdateStrategy(SwPatchManagerMixin,
sw_update_manager.AbortSwUpdateStrategy):
"""Abort a patch update strategy."""
pass

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# Copyright (c) 2017 Wind River Systems, Inc. # Copyright (c) 2020 Wind River Systems, Inc.
# #
# The right to copy, distribute, modify, or otherwise make use # The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms # of this software may be licensed only pursuant to the terms
@ -22,9 +22,16 @@
from dcmanagerclient.commands.v1 import base from dcmanagerclient.commands.v1 import base
from dcmanagerclient import exceptions from dcmanagerclient import exceptions
# These are the abstract base classes used for sw update managers such as
# - sw-patch-manager
# - fw-update-manager
#
# also handles 'steps' and 'strategies'
def detail_format(sw_update_strategy=None): def detail_format(sw_update_strategy=None):
columns = ( columns = (
'strategy type',
'subcloud apply type', 'subcloud apply type',
'max parallel subclouds', 'max parallel subclouds',
'stop on failure', 'stop on failure',
@ -35,6 +42,7 @@ def detail_format(sw_update_strategy=None):
if sw_update_strategy: if sw_update_strategy:
data = ( data = (
sw_update_strategy.strategy_type,
sw_update_strategy.subcloud_apply_type, sw_update_strategy.subcloud_apply_type,
sw_update_strategy.max_parallel_subclouds, sw_update_strategy.max_parallel_subclouds,
sw_update_strategy.stop_on_failure, sw_update_strategy.stop_on_failure,
@ -104,14 +112,18 @@ def detail_strategy_step_format(strategy_step=None):
return columns, data return columns, data
class CreatePatchStrategy(base.DCManagerShowOne): class CreateSwUpdateStrategy(base.DCManagerShowOne):
"""Create a patch strategy.""" """Create a software update strategy."""
def get_sw_update_manager(self):
# This method must be overrridden by the concrete subclass
raise NotImplementedError
def _get_format_function(self): def _get_format_function(self):
return detail_format return detail_format
def get_parser(self, prog_name): def get_parser(self, prog_name):
parser = super(CreatePatchStrategy, self).get_parser(prog_name) parser = super(CreateSwUpdateStrategy, self).get_parser(prog_name)
parser.add_argument( parser.add_argument(
'--subcloud-apply-type', '--subcloud-apply-type',
@ -131,20 +143,18 @@ class CreatePatchStrategy(base.DCManagerShowOne):
'--stop-on-failure', '--stop-on-failure',
required=False, required=False,
action='store_true', action='store_true',
help='Do not patch any additional subclouds after a failure.' help='Do not update any additional subclouds after a failure.'
) )
parser.add_argument( parser.add_argument(
'cloud_name', 'cloud_name',
nargs='?', nargs='?',
default=None, default=None,
help='Name of a single cloud to patch.' help='Name of a single cloud to update.'
) )
return parser return parser
def _get_resources(self, parsed_args): def _get_resources(self, parsed_args):
dcmanager_client = self.app.client_manager.sw_update_manager
kwargs = dict() kwargs = dict()
if parsed_args.subcloud_apply_type: if parsed_args.subcloud_apply_type:
kwargs['subcloud-apply-type'] = parsed_args.subcloud_apply_type kwargs['subcloud-apply-type'] = parsed_args.subcloud_apply_type
@ -155,118 +165,114 @@ class CreatePatchStrategy(base.DCManagerShowOne):
kwargs['stop-on-failure'] = 'true' kwargs['stop-on-failure'] = 'true'
if parsed_args.cloud_name is not None: if parsed_args.cloud_name is not None:
kwargs['cloud_name'] = parsed_args.cloud_name kwargs['cloud_name'] = parsed_args.cloud_name
return dcmanager_client.sw_update_manager.create_patch_strategy( return self.get_sw_update_manager().create_sw_update_strategy(**kwargs)
**kwargs)
class ShowPatchStrategy(base.DCManagerShowOne): class ShowSwUpdateStrategy(base.DCManagerShowOne):
"""Show the details of a patch strategy for a subcloud.""" """Show the details of an software update strategy for a subcloud."""
def get_sw_update_manager(self):
# This method must be overrridden by the concrete subclass
raise NotImplementedError
def _get_format_function(self): def _get_format_function(self):
return detail_format return detail_format
def get_parser(self, prog_name):
parser = super(ShowPatchStrategy, self).get_parser(prog_name)
return parser
def _get_resources(self, parsed_args): def _get_resources(self, parsed_args):
dcmanager_client = self.app.client_manager.sw_update_manager return self.get_sw_update_manager().update_sw_strategy_detail()
return dcmanager_client.sw_update_manager.patch_strategy_detail()
class DeletePatchStrategy(base.DCManagerShowOne): class DeleteSwUpdateStrategy(base.DCManagerShowOne):
"""Delete patch strategy from the database.""" """Delete a software update strategy from the database."""
def get_sw_update_manager(self):
# This method must be overrridden by the concrete subclass
raise NotImplementedError
def _get_format_function(self): def _get_format_function(self):
return detail_format return detail_format
def get_parser(self, prog_name):
parser = super(DeletePatchStrategy, self).get_parser(prog_name)
return parser
def _get_resources(self, parsed_args): def _get_resources(self, parsed_args):
dcmanager_client = self.app.client_manager.sw_update_manager
try: try:
return dcmanager_client.sw_update_manager.delete_patch_strategy() return self.get_sw_update_manager().delete_sw_update_strategy()
except Exception as e: except Exception as e:
print(e) print(e)
error_msg = "Unable to delete patch strategy" error_msg = "Unable to delete sw update strategy"
raise exceptions.DCManagerClientException(error_msg) raise exceptions.DCManagerClientException(error_msg)
class ApplyPatchStrategy(base.DCManagerShowOne): class ApplySwUpdateStrategy(base.DCManagerShowOne):
"""Apply a patch strategy.""" """Apply a software update strategy."""
def get_sw_update_manager(self):
# This method must be overrridden by the concrete subclass
raise NotImplementedError
def _get_format_function(self): def _get_format_function(self):
return detail_format return detail_format
def get_parser(self, prog_name):
parser = super(ApplyPatchStrategy, self).get_parser(prog_name)
return parser
def _get_resources(self, parsed_args): def _get_resources(self, parsed_args):
dcmanager_client = self.app.client_manager.sw_update_manager
try: try:
return dcmanager_client.sw_update_manager.apply_patch_strategy() return self.get_sw_update_manager().apply_sw_update_strategy()
except Exception as e: except Exception as e:
print(e) print(e)
error_msg = "Unable to apply patch strategy" error_msg = "Unable to apply sw update strategy"
raise exceptions.DCManagerClientException(error_msg) raise exceptions.DCManagerClientException(error_msg)
class AbortPatchStrategy(base.DCManagerShowOne): class AbortSwUpdateStrategy(base.DCManagerShowOne):
"""Abort a patch strategy.""" """Abort a software update strategy."""
def get_sw_update_manager(self):
# This method must be overrridden by the concrete subclass
raise NotImplementedError
def _get_format_function(self): def _get_format_function(self):
return detail_format return detail_format
def get_parser(self, prog_name):
parser = super(AbortPatchStrategy, self).get_parser(prog_name)
return parser
def _get_resources(self, parsed_args): def _get_resources(self, parsed_args):
dcmanager_client = self.app.client_manager.sw_update_manager
try: try:
return dcmanager_client.sw_update_manager.abort_patch_strategy() return self.get_sw_update_manager().abort_sw_update_strategy()
except Exception as e: except Exception as e:
print(e) print(e)
error_msg = "Unable to abort patch strategy" error_msg = "Unable to abort sw update strategy"
raise exceptions.DCManagerClientException(error_msg) raise exceptions.DCManagerClientException(error_msg)
class ListStrategyStep(base.DCManagerLister): class ListSwUpdateStrategyStep(base.DCManagerLister):
"""List strategy steps.""" """List strategy steps."""
def get_strategy_step_manager(self):
dcmanager_client = self.app.client_manager.strategy_step_manager
return dcmanager_client.strategy_step_manager
def _get_format_function(self): def _get_format_function(self):
return strategy_step_format return strategy_step_format
def get_parser(self, prog_name):
parser = super(ListStrategyStep, self).get_parser(prog_name)
return parser
def _get_resources(self, parsed_args): def _get_resources(self, parsed_args):
dcmanager_client = self.app.client_manager.strategy_step_manager return self.get_strategy_step_manager().list_strategy_steps()
return dcmanager_client.strategy_step_manager.list_strategy_steps()
class ShowStrategyStep(base.DCManagerShowOne): class ShowSwUpdateStrategyStep(base.DCManagerShowOne):
"""Show the details of a strategy step.""" """Show the details of a strategy step."""
def get_strategy_step_manager(self):
dcmanager_client = self.app.client_manager.strategy_step_manager
return dcmanager_client.strategy_step_manager
def _get_format_function(self): def _get_format_function(self):
return detail_strategy_step_format return detail_strategy_step_format
def get_parser(self, prog_name): def get_parser(self, prog_name):
parser = super(ShowStrategyStep, self).get_parser(prog_name) parser = super(ShowSwUpdateStrategyStep, self).get_parser(prog_name)
parser.add_argument( parser.add_argument(
'cloud_name', 'cloud_name',
help='Name of cloud to view the details.' help='Name of cloud to view the details.'
) )
return parser return parser
def _get_resources(self, parsed_args): def _get_resources(self, parsed_args):
cloud_name = parsed_args.cloud_name cloud_name = parsed_args.cloud_name
dcmanager_client = self.app.client_manager.strategy_step_manager return self.get_strategy_step_manager().strategy_step_detail(
return dcmanager_client.strategy_step_manager.strategy_step_detail(
cloud_name) cloud_name)

View File

@ -0,0 +1,59 @@
# Copyright (c) 2017 Ericsson AB.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
from dcmanagerclient.commands.v1 import sw_update_manager
class SwUpgradeManagerMixin(object):
"""This Mixin provides the update manager used for software upgrades."""
def get_sw_update_manager(self):
dcmanager_client = self.app.client_manager.sw_upgrade_manager
return dcmanager_client.sw_upgrade_manager
class CreateSwUpgradeStrategy(SwUpgradeManagerMixin,
sw_update_manager.CreateSwUpdateStrategy):
"""Create a software upgrade strategy."""
pass
class ShowSwUpgradeStrategy(SwUpgradeManagerMixin,
sw_update_manager.ShowSwUpdateStrategy):
"""Show the details of a software upgrade strategy for a subcloud."""
pass
class DeleteSwUpgradeStrategy(SwUpgradeManagerMixin,
sw_update_manager.DeleteSwUpdateStrategy):
"""Delete software upgrade strategy from the database."""
pass
class ApplySwUpgradeStrategy(SwUpgradeManagerMixin,
sw_update_manager.ApplySwUpdateStrategy):
"""Apply a software upgrade strategy."""
pass
class AbortSwUpgradeStrategy(SwUpgradeManagerMixin,
sw_update_manager.AbortSwUpdateStrategy):
"""Abort a software upgrade strategy."""
pass

View File

@ -37,11 +37,14 @@ from osc_lib.command import command
import argparse import argparse
from dcmanagerclient.commands.v1 import alarm_manager as am from dcmanagerclient.commands.v1 import alarm_manager as am
# from dcmanagerclient.commands.v1 import fw_update_manager as fum
from dcmanagerclient.commands.v1 import subcloud_deploy_manager as sdm from dcmanagerclient.commands.v1 import subcloud_deploy_manager as sdm
from dcmanagerclient.commands.v1 import subcloud_group_manager as gm from dcmanagerclient.commands.v1 import subcloud_group_manager as gm
from dcmanagerclient.commands.v1 import subcloud_manager as sm from dcmanagerclient.commands.v1 import subcloud_manager as sm
from dcmanagerclient.commands.v1 import sw_patch_manager as spm
from dcmanagerclient.commands.v1 import sw_update_manager as sum from dcmanagerclient.commands.v1 import sw_update_manager as sum
from dcmanagerclient.commands.v1 import sw_update_options_manager as suom from dcmanagerclient.commands.v1 import sw_update_options_manager as suom
from dcmanagerclient.commands.v1 import sw_upgrade_manager as supm
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -449,9 +452,11 @@ class DCManagerShell(app.App):
subcloud_group_manager=self.client, subcloud_group_manager=self.client,
subcloud_deploy_manager=self.client, subcloud_deploy_manager=self.client,
alarm_manager=self.client, alarm_manager=self.client,
sw_update_manager=self.client, fw_update_manager=self.client,
sw_patch_manager=self.client,
strategy_step_manager=self.client, strategy_step_manager=self.client,
sw_update_options_manager=self.client) sw_update_options_manager=self.client,
sw_upgrade_manager=self.client)
) )
self.client_manager = ClientManager() self.client_manager = ClientManager()
@ -493,17 +498,31 @@ class DCManagerShell(app.App):
'subcloud-deploy upload': sdm.SubcloudDeployUpload, 'subcloud-deploy upload': sdm.SubcloudDeployUpload,
'subcloud-deploy show': sdm.SubcloudDeployShow, 'subcloud-deploy show': sdm.SubcloudDeployShow,
'alarm summary': am.ListAlarmSummary, 'alarm summary': am.ListAlarmSummary,
'patch-strategy create': sum.CreatePatchStrategy, # 'fw-update-strategy create': fum.CreateFwUpdateStrategy,
'patch-strategy delete': sum.DeletePatchStrategy, # 'fw-update-strategy delete': fum.DeleteFwUpdateStrategy,
'patch-strategy apply': sum.ApplyPatchStrategy, # 'fw-update-strategy apply': fum.ApplyFwUpdateStrategy,
'patch-strategy abort': sum.AbortPatchStrategy, # 'fw-update-strategy abort': fum.AbortFwUpdateStrategy,
'patch-strategy show': sum.ShowPatchStrategy, # 'fw-update-strategy show': fum.ShowFwUpdateStrategy,
'strategy-step list': sum.ListStrategyStep, 'patch-strategy create': spm.CreatePatchUpdateStrategy,
'strategy-step show': sum.ShowStrategyStep, 'patch-strategy delete': spm.DeletePatchUpdateStrategy,
'patch-strategy apply': spm.ApplyPatchUpdateStrategy,
'patch-strategy abort': spm.AbortPatchUpdateStrategy,
'patch-strategy show': spm.ShowPatchUpdateStrategy,
'strategy-step list': sum.ListSwUpdateStrategyStep,
'strategy-step show': sum.ShowSwUpdateStrategyStep,
'patch-strategy-config update': suom.UpdateSwUpdateOptions, 'patch-strategy-config update': suom.UpdateSwUpdateOptions,
'patch-strategy-config list': suom.ListSwUpdateOptions, 'patch-strategy-config list': suom.ListSwUpdateOptions,
'patch-strategy-config show': suom.ShowSwUpdateOptions, 'patch-strategy-config show': suom.ShowSwUpdateOptions,
'patch-strategy-config delete': suom.DeleteSwUpdateOptions, 'patch-strategy-config delete': suom.DeleteSwUpdateOptions,
'strategy-config update': suom.UpdateSwUpdateOptions,
'strategy-config list': suom.ListSwUpdateOptions,
'strategy-config show': suom.ShowSwUpdateOptions,
'strategy-config delete': suom.DeleteSwUpdateOptions,
'upgrade-strategy create': supm.CreateSwUpgradeStrategy,
'upgrade-strategy delete': supm.DeleteSwUpgradeStrategy,
'upgrade-strategy apply': supm.ApplySwUpgradeStrategy,
'upgrade-strategy abort': supm.AbortSwUpgradeStrategy,
'upgrade-strategy show': supm.ShowSwUpgradeStrategy,
} }

View File

@ -0,0 +1,68 @@
# Copyright (c) 2017 Ericsson AB.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
import mock
from oslo_utils import timeutils
from dcmanagerclient.api.v1.strategy_step_manager import StrategyStep
from dcmanagerclient.commands.v1 import sw_update_manager as cli_cmd
from dcmanagerclient.tests import base
TEST_CLOUD_ID = 1
TEST_STAGE = 1
TEST_STATE = 'initializing'
TEST_DETAILS = 'some details'
TIME_NOW = timeutils.utcnow().isoformat()
TEST_STARTED_AT = TIME_NOW
TEST_FINISHED_AT = TIME_NOW
TEST_CREATED_AT = TIME_NOW
TEST_UPDATED_AT = TIME_NOW
class TestCLI(base.BaseCommandTest):
def setUp(self):
super(TestCLI, self).setUp()
def test_list_strategy_steps(self):
sample_step = StrategyStep(mock,
TEST_CLOUD_ID,
TEST_STAGE,
TEST_STATE,
TEST_DETAILS,
TEST_STARTED_AT,
TEST_FINISHED_AT,
TEST_CREATED_AT,
TEST_UPDATED_AT)
results = []
results.append(sample_step)
self.app.client_manager.strategy_step_manager.strategy_step_manager.\
list_strategy_steps.return_value = results
actual_call = self.call(cli_cmd.ListSwUpdateStrategyStep)
# ListStrategyStep returns a tuple, want the second field of the tuple
result_steps = actual_call[1]
# Only 1 step
self.assertEqual(1, len(result_steps))
# The step object is a tuple based on the formatter
for step in result_steps:
self.assertEqual(TEST_CLOUD_ID, step[0])