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:
parent
19f027179c
commit
c640a51440
|
@ -20,23 +20,22 @@
|
|||
# of this software may be licensed only pursuant to the terms
|
||||
# of an applicable Wind River license agreement.
|
||||
#
|
||||
import six
|
||||
|
||||
import keystoneauth1.identity.generic as auth_plugin
|
||||
from keystoneauth1 import session as ks_session
|
||||
import osprofiler.profiler
|
||||
|
||||
from dcmanagerclient.api import httpclient
|
||||
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_group_manager as gm
|
||||
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
|
||||
|
||||
|
||||
import osprofiler.profiler
|
||||
|
||||
import six
|
||||
|
||||
from dcmanagerclient.api.v1 import sw_upgrade_manager as supm
|
||||
|
||||
_DEFAULT_DCMANAGER_URL = "http://localhost:8119/v1.0"
|
||||
|
||||
|
@ -102,11 +101,13 @@ class Client(object):
|
|||
self.subcloud_deploy_manager = sdm.subcloud_deploy_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 = \
|
||||
suom.sw_update_options_manager(self.http_client)
|
||||
self.strategy_step_manager = sum.strategy_step_manager(
|
||||
self.http_client)
|
||||
self.sw_upgrade_manager = supm.sw_upgrade_manager(self.http_client)
|
||||
self.strategy_step_manager = \
|
||||
ssm.strategy_step_manager(self.http_client)
|
||||
|
||||
|
||||
def authenticate(dcmanager_url=None, username=None,
|
||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
|
@ -26,13 +26,21 @@ from dcmanagerclient.api import base
|
|||
from dcmanagerclient.api.base import get_json
|
||||
|
||||
|
||||
# todo(abailey): Update SwUpdateStrategy based on 'subcloud group'
|
||||
class SwUpdateStrategy(base.Resource):
|
||||
resource_name = 'sw_update_strategy'
|
||||
|
||||
def __init__(self, manager, subcloud_apply_type, max_parallel_subclouds,
|
||||
stop_on_failure, state,
|
||||
created_at, updated_at):
|
||||
def __init__(self,
|
||||
manager,
|
||||
strategy_type,
|
||||
subcloud_apply_type,
|
||||
max_parallel_subclouds,
|
||||
stop_on_failure,
|
||||
state,
|
||||
created_at,
|
||||
updated_at):
|
||||
self.manager = manager
|
||||
self.strategy_type = strategy_type
|
||||
self.subcloud_apply_type = subcloud_apply_type
|
||||
self.max_parallel_subclouds = max_parallel_subclouds
|
||||
self.stop_on_failure = stop_on_failure
|
||||
|
@ -41,169 +49,94 @@ class SwUpdateStrategy(base.Resource):
|
|||
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):
|
||||
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.update({'type': 'patch'})
|
||||
url = '/sw-update-strategy/'
|
||||
return self.sw_update_create(url, data)
|
||||
data.update({'type': self.update_type})
|
||||
return self._sw_update_create(self.create_url, data)
|
||||
|
||||
def patch_strategy_detail(self):
|
||||
url = '/sw-update-strategy'
|
||||
return self.sw_update_detail(url)
|
||||
def update_sw_strategy_detail(self):
|
||||
return self._sw_update_detail(self.get_url)
|
||||
|
||||
def delete_patch_strategy(self):
|
||||
url = '/sw-update-strategy'
|
||||
return self.sw_update_delete(url)
|
||||
def delete_sw_update_strategy(self):
|
||||
return self._sw_update_delete(self.delete_url)
|
||||
|
||||
def apply_patch_strategy(self):
|
||||
def apply_sw_update_strategy(self):
|
||||
data = {'action': 'apply'}
|
||||
url = '/sw-update-strategy/actions'
|
||||
return self.sw_update_action(url, data)
|
||||
return self._sw_update_action(self.actions_url, data)
|
||||
|
||||
def abort_patch_strategy(self):
|
||||
def abort_sw_update_strategy(self):
|
||||
data = {'action': 'abort'}
|
||||
url = '/sw-update-strategy/actions'
|
||||
return self.sw_update_action(url, data)
|
||||
return self._sw_update_action(self.actions_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)
|
||||
resp = self.http_client.post(url, data)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
json_object = get_json(resp)
|
||||
resource = list()
|
||||
resource.append(
|
||||
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']))
|
||||
resource.append(self._build_from_json(json_object))
|
||||
return resource
|
||||
|
||||
def sw_update_delete(self, url):
|
||||
def _sw_update_delete(self, url):
|
||||
resp = self.http_client.delete(url)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
json_object = get_json(resp)
|
||||
resource = list()
|
||||
resource.append(
|
||||
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']))
|
||||
resource.append(self._build_from_json(json_object))
|
||||
return resource
|
||||
|
||||
def sw_update_detail(self, url):
|
||||
def _sw_update_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,
|
||||
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']))
|
||||
resource.append(self._build_from_json(json_object))
|
||||
return resource
|
||||
|
||||
def sw_update_action(self, url, data):
|
||||
def _sw_update_action(self, url, data):
|
||||
data = json.dumps(data)
|
||||
resp = self.http_client.post(url, data)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
json_object = get_json(resp)
|
||||
resource = list()
|
||||
resource.append(
|
||||
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'],
|
||||
))
|
||||
resource.append(self._build_from_json(json_object))
|
||||
return resource
|
||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -12,7 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# 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
|
||||
# of this software may be licensed only pursuant to the terms
|
||||
|
@ -22,9 +22,16 @@
|
|||
from dcmanagerclient.commands.v1 import base
|
||||
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):
|
||||
columns = (
|
||||
'strategy type',
|
||||
'subcloud apply type',
|
||||
'max parallel subclouds',
|
||||
'stop on failure',
|
||||
|
@ -35,6 +42,7 @@ def detail_format(sw_update_strategy=None):
|
|||
|
||||
if sw_update_strategy:
|
||||
data = (
|
||||
sw_update_strategy.strategy_type,
|
||||
sw_update_strategy.subcloud_apply_type,
|
||||
sw_update_strategy.max_parallel_subclouds,
|
||||
sw_update_strategy.stop_on_failure,
|
||||
|
@ -104,14 +112,18 @@ def detail_strategy_step_format(strategy_step=None):
|
|||
return columns, data
|
||||
|
||||
|
||||
class CreatePatchStrategy(base.DCManagerShowOne):
|
||||
"""Create a patch strategy."""
|
||||
class CreateSwUpdateStrategy(base.DCManagerShowOne):
|
||||
"""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):
|
||||
return detail_format
|
||||
|
||||
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(
|
||||
'--subcloud-apply-type',
|
||||
|
@ -131,20 +143,18 @@ class CreatePatchStrategy(base.DCManagerShowOne):
|
|||
'--stop-on-failure',
|
||||
required=False,
|
||||
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(
|
||||
'cloud_name',
|
||||
nargs='?',
|
||||
default=None,
|
||||
help='Name of a single cloud to patch.'
|
||||
help='Name of a single cloud to update.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
dcmanager_client = self.app.client_manager.sw_update_manager
|
||||
kwargs = dict()
|
||||
if 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'
|
||||
if parsed_args.cloud_name is not None:
|
||||
kwargs['cloud_name'] = parsed_args.cloud_name
|
||||
return dcmanager_client.sw_update_manager.create_patch_strategy(
|
||||
**kwargs)
|
||||
return self.get_sw_update_manager().create_sw_update_strategy(**kwargs)
|
||||
|
||||
|
||||
class ShowPatchStrategy(base.DCManagerShowOne):
|
||||
"""Show the details of a patch strategy for a subcloud."""
|
||||
class ShowSwUpdateStrategy(base.DCManagerShowOne):
|
||||
"""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):
|
||||
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):
|
||||
dcmanager_client = self.app.client_manager.sw_update_manager
|
||||
return dcmanager_client.sw_update_manager.patch_strategy_detail()
|
||||
return self.get_sw_update_manager().update_sw_strategy_detail()
|
||||
|
||||
|
||||
class DeletePatchStrategy(base.DCManagerShowOne):
|
||||
"""Delete patch strategy from the database."""
|
||||
class DeleteSwUpdateStrategy(base.DCManagerShowOne):
|
||||
"""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):
|
||||
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):
|
||||
dcmanager_client = self.app.client_manager.sw_update_manager
|
||||
try:
|
||||
return dcmanager_client.sw_update_manager.delete_patch_strategy()
|
||||
return self.get_sw_update_manager().delete_sw_update_strategy()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_msg = "Unable to delete patch strategy"
|
||||
error_msg = "Unable to delete sw update strategy"
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
|
||||
class ApplyPatchStrategy(base.DCManagerShowOne):
|
||||
"""Apply a patch strategy."""
|
||||
class ApplySwUpdateStrategy(base.DCManagerShowOne):
|
||||
"""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):
|
||||
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):
|
||||
dcmanager_client = self.app.client_manager.sw_update_manager
|
||||
try:
|
||||
return dcmanager_client.sw_update_manager.apply_patch_strategy()
|
||||
return self.get_sw_update_manager().apply_sw_update_strategy()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_msg = "Unable to apply patch strategy"
|
||||
error_msg = "Unable to apply sw update strategy"
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
|
||||
class AbortPatchStrategy(base.DCManagerShowOne):
|
||||
"""Abort a patch strategy."""
|
||||
class AbortSwUpdateStrategy(base.DCManagerShowOne):
|
||||
"""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):
|
||||
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):
|
||||
dcmanager_client = self.app.client_manager.sw_update_manager
|
||||
try:
|
||||
return dcmanager_client.sw_update_manager.abort_patch_strategy()
|
||||
return self.get_sw_update_manager().abort_sw_update_strategy()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_msg = "Unable to abort patch strategy"
|
||||
error_msg = "Unable to abort sw update strategy"
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
|
||||
class ListStrategyStep(base.DCManagerLister):
|
||||
class ListSwUpdateStrategyStep(base.DCManagerLister):
|
||||
"""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):
|
||||
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):
|
||||
dcmanager_client = self.app.client_manager.strategy_step_manager
|
||||
return dcmanager_client.strategy_step_manager.list_strategy_steps()
|
||||
return self.get_strategy_step_manager().list_strategy_steps()
|
||||
|
||||
|
||||
class ShowStrategyStep(base.DCManagerShowOne):
|
||||
class ShowSwUpdateStrategyStep(base.DCManagerShowOne):
|
||||
"""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):
|
||||
return detail_strategy_step_format
|
||||
|
||||
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(
|
||||
'cloud_name',
|
||||
help='Name of cloud to view the details.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
cloud_name = parsed_args.cloud_name
|
||||
dcmanager_client = self.app.client_manager.strategy_step_manager
|
||||
return dcmanager_client.strategy_step_manager.strategy_step_detail(
|
||||
return self.get_strategy_step_manager().strategy_step_detail(
|
||||
cloud_name)
|
||||
|
|
|
@ -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
|
|
@ -37,11 +37,14 @@ from osc_lib.command import command
|
|||
|
||||
import argparse
|
||||
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_group_manager as gm
|
||||
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_options_manager as suom
|
||||
from dcmanagerclient.commands.v1 import sw_upgrade_manager as supm
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -449,9 +452,11 @@ class DCManagerShell(app.App):
|
|||
subcloud_group_manager=self.client,
|
||||
subcloud_deploy_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,
|
||||
sw_update_options_manager=self.client)
|
||||
sw_update_options_manager=self.client,
|
||||
sw_upgrade_manager=self.client)
|
||||
)
|
||||
self.client_manager = ClientManager()
|
||||
|
||||
|
@ -493,17 +498,31 @@ class DCManagerShell(app.App):
|
|||
'subcloud-deploy upload': sdm.SubcloudDeployUpload,
|
||||
'subcloud-deploy show': sdm.SubcloudDeployShow,
|
||||
'alarm summary': am.ListAlarmSummary,
|
||||
'patch-strategy create': sum.CreatePatchStrategy,
|
||||
'patch-strategy delete': sum.DeletePatchStrategy,
|
||||
'patch-strategy apply': sum.ApplyPatchStrategy,
|
||||
'patch-strategy abort': sum.AbortPatchStrategy,
|
||||
'patch-strategy show': sum.ShowPatchStrategy,
|
||||
'strategy-step list': sum.ListStrategyStep,
|
||||
'strategy-step show': sum.ShowStrategyStep,
|
||||
# 'fw-update-strategy create': fum.CreateFwUpdateStrategy,
|
||||
# 'fw-update-strategy delete': fum.DeleteFwUpdateStrategy,
|
||||
# 'fw-update-strategy apply': fum.ApplyFwUpdateStrategy,
|
||||
# 'fw-update-strategy abort': fum.AbortFwUpdateStrategy,
|
||||
# 'fw-update-strategy show': fum.ShowFwUpdateStrategy,
|
||||
'patch-strategy create': spm.CreatePatchUpdateStrategy,
|
||||
'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 list': suom.ListSwUpdateOptions,
|
||||
'patch-strategy-config show': suom.ShowSwUpdateOptions,
|
||||
'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,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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])
|
Loading…
Reference in New Issue