Merge remote-tracking branch 'gerrit/master' into f/centos8
Change-Id: I085b3b0b91b95c3594f373acbaebc18778e7f6a3
This commit is contained in:
commit
47ca1dc885
11
.zuul.yaml
11
.zuul.yaml
|
@ -8,11 +8,13 @@
|
|||
- openstack-tox-linters
|
||||
- stx-distcloud-client-tox-pep8
|
||||
- stx-distcloud-client-tox-py27
|
||||
- stx-distcloud-client-tox-pylint
|
||||
gate:
|
||||
jobs:
|
||||
- openstack-tox-linters
|
||||
- stx-distcloud-client-tox-pep8
|
||||
- stx-distcloud-client-tox-py27
|
||||
- stx-distcloud-client-tox-pylint
|
||||
post:
|
||||
jobs:
|
||||
- stx-distcloud-client-upload-git-mirror
|
||||
|
@ -25,6 +27,15 @@
|
|||
tox_envlist: py27
|
||||
tox_extra_args: -c distributedcloud-client/tox.ini
|
||||
|
||||
- job:
|
||||
name: stx-distcloud-client-tox-pylint
|
||||
parent: tox
|
||||
description: Run pylint for distcloud-client
|
||||
vars:
|
||||
tox_envlist: pylint
|
||||
tox_extra_args: -c distributedcloud-client/tox.ini
|
||||
|
||||
|
||||
- job:
|
||||
name: stx-distcloud-client-tox-pep8
|
||||
parent: tox
|
||||
|
|
|
@ -44,6 +44,7 @@ BuildRequires: python3-sphinx
|
|||
BuildRequires: python3-pyOpenSSL
|
||||
BuildRequires: systemd
|
||||
BuildRequires: git
|
||||
BuildRequires: requests-toolbelt
|
||||
# Required to compile translation files
|
||||
BuildRequires: python3-babel
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ LOG = logging.getLogger(__name__)
|
|||
def log_request(func):
|
||||
def decorator(self, *args, **kwargs):
|
||||
resp = func(self, *args, **kwargs)
|
||||
LOG.debug("HTTP %s %s %d" % (resp.request.method, resp.url,
|
||||
resp.status_code))
|
||||
LOG.debug("HTTP %s %s %d %s" % (resp.request.method, resp.url,
|
||||
resp.status_code, resp.text))
|
||||
return resp
|
||||
|
||||
return decorator
|
||||
|
|
|
@ -14,27 +14,28 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright (c) 2017 Wind River Systems, Inc.
|
||||
# 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.
|
||||
#
|
||||
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"
|
||||
|
||||
|
@ -95,12 +96,18 @@ class Client(object):
|
|||
|
||||
# Create all managers
|
||||
self.subcloud_manager = sm.subcloud_manager(self.http_client)
|
||||
self.subcloud_group_manager = \
|
||||
gm.subcloud_group_manager(self.http_client, self.subcloud_manager)
|
||||
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,79 @@
|
|||
# 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 requests_toolbelt import MultipartEncoder
|
||||
|
||||
from dcmanagerclient.api import base
|
||||
from dcmanagerclient.api.base import get_json
|
||||
|
||||
|
||||
class SubcloudDeploy(base.Resource):
|
||||
resource_name = 'subcloud_deploy'
|
||||
|
||||
def __init__(self, deploy_playbook, deploy_overrides, deploy_chart):
|
||||
self.deploy_playbook = deploy_playbook
|
||||
self.deploy_overrides = deploy_overrides
|
||||
self.deploy_chart = deploy_chart
|
||||
|
||||
|
||||
class subcloud_deploy_manager(base.ResourceManager):
|
||||
resource_class = SubcloudDeploy
|
||||
|
||||
def _subcloud_deploy_detail(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_object = json_response_key['subcloud_deploy']
|
||||
resource = list()
|
||||
resource.append(
|
||||
self.resource_class(
|
||||
deploy_playbook=json_object['deploy_playbook'],
|
||||
deploy_overrides=json_object['deploy_overrides'],
|
||||
deploy_chart=json_object['deploy_chart']))
|
||||
return resource
|
||||
|
||||
def _deploy_upload(self, url, data):
|
||||
fields = dict()
|
||||
for k, v in data.items():
|
||||
fields.update({k: (v, open(v, 'rb'),)})
|
||||
enc = MultipartEncoder(fields=fields)
|
||||
headers = {'Content-Type': enc.content_type}
|
||||
resp = self.http_client.post(url, enc, headers=headers)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
json_object = get_json(resp)
|
||||
resource = list()
|
||||
resource.append(
|
||||
self.resource_class(
|
||||
deploy_playbook=json_object['deploy_playbook'],
|
||||
deploy_overrides=json_object['deploy_overrides'],
|
||||
deploy_chart=json_object['deploy_chart']))
|
||||
return resource
|
||||
|
||||
def subcloud_deploy_show(self):
|
||||
url = '/subcloud-deploy/'
|
||||
return self._subcloud_deploy_detail(url)
|
||||
|
||||
def subcloud_deploy_upload(self, **kwargs):
|
||||
data = kwargs
|
||||
url = '/subcloud-deploy/'
|
||||
return self._deploy_upload(url, data)
|
|
@ -0,0 +1,145 @@
|
|||
# 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.
|
||||
#
|
||||
|
||||
import json
|
||||
|
||||
from dcmanagerclient.api import base
|
||||
from dcmanagerclient.api.base import get_json
|
||||
|
||||
|
||||
class SubcloudGroup(base.Resource):
|
||||
resource_name = 'subcloud_group'
|
||||
|
||||
def __init__(self,
|
||||
manager,
|
||||
group_id,
|
||||
name,
|
||||
description,
|
||||
update_apply_type,
|
||||
max_parallel_subclouds,
|
||||
created_at,
|
||||
updated_at):
|
||||
self.manager = manager
|
||||
self.group_id = group_id
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.update_apply_type = update_apply_type
|
||||
self.max_parallel_subclouds = max_parallel_subclouds
|
||||
self.created_at = created_at
|
||||
self.updated_at = updated_at
|
||||
|
||||
|
||||
class subcloud_group_manager(base.ResourceManager):
|
||||
resource_class = SubcloudGroup
|
||||
|
||||
def __init__(self, http_client, subcloud_manager):
|
||||
super(subcloud_group_manager, self).__init__(http_client)
|
||||
self.subcloud_manager = subcloud_manager
|
||||
|
||||
def _json_to_resource(self, json_object):
|
||||
return self.resource_class(
|
||||
self,
|
||||
group_id=json_object['id'],
|
||||
name=json_object['name'],
|
||||
description=json_object['description'],
|
||||
update_apply_type=json_object['update_apply_type'],
|
||||
max_parallel_subclouds=json_object['max_parallel_subclouds'],
|
||||
created_at=json_object['created-at'],
|
||||
updated_at=json_object['updated-at'])
|
||||
|
||||
def subcloud_group_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._json_to_resource(json_object))
|
||||
return resource
|
||||
|
||||
def subcloud_group_update(self, url, data):
|
||||
data = json.dumps(data)
|
||||
resp = self.http_client.patch(url, data)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
json_object = get_json(resp)
|
||||
resource = list()
|
||||
resource.append(self._json_to_resource(json_object))
|
||||
return resource
|
||||
|
||||
def subcloud_group_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['subcloud_groups']
|
||||
resource = []
|
||||
for json_object in json_objects:
|
||||
resource.append(self._json_to_resource(json_object))
|
||||
return resource
|
||||
|
||||
def _subcloud_group_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._json_to_resource(json_object))
|
||||
return resource
|
||||
|
||||
def _list_subclouds_for_subcloud_group(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['subclouds']
|
||||
resource = []
|
||||
for json_object in json_objects:
|
||||
resource.append(
|
||||
self.subcloud_manager.json_to_resource(json_object))
|
||||
return resource
|
||||
|
||||
def add_subcloud_group(self, **kwargs):
|
||||
data = kwargs
|
||||
url = '/subcloud-groups/'
|
||||
return self.subcloud_group_create(url, data)
|
||||
|
||||
def list_subcloud_groups(self):
|
||||
url = '/subcloud-groups/'
|
||||
return self.subcloud_group_list(url)
|
||||
|
||||
def subcloud_group_list_subclouds(self, subcloud_group_ref):
|
||||
url = '/subcloud-groups/%s/subclouds' % subcloud_group_ref
|
||||
return self._list_subclouds_for_subcloud_group(url)
|
||||
|
||||
def subcloud_group_detail(self, subcloud_group_ref):
|
||||
url = '/subcloud-groups/%s' % subcloud_group_ref
|
||||
return self._subcloud_group_detail(url)
|
||||
|
||||
def delete_subcloud_group(self, subcloud_group_ref):
|
||||
url = '/subcloud-groups/%s' % subcloud_group_ref
|
||||
return self._delete(url)
|
||||
|
||||
def update_subcloud_group(self, subcloud_group_ref, **kwargs):
|
||||
data = kwargs
|
||||
url = '/subcloud-groups/%s' % subcloud_group_ref
|
||||
return self.subcloud_group_update(url, data)
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
import json
|
||||
|
||||
from requests_toolbelt import MultipartEncoder
|
||||
|
||||
from dcmanagerclient.api import base
|
||||
from dcmanagerclient.api.base import get_json
|
||||
|
||||
|
@ -34,7 +36,7 @@ class Subcloud(base.Resource):
|
|||
deploy_status,
|
||||
management_subnet, management_start_ip, management_end_ip,
|
||||
management_gateway_ip, systemcontroller_gateway_ip,
|
||||
created_at, updated_at, sync_status="unknown",
|
||||
created_at, updated_at, group_id, sync_status="unknown",
|
||||
endpoint_sync_status={}):
|
||||
self.manager = manager
|
||||
self.subcloud_id = subcloud_id
|
||||
|
@ -53,6 +55,7 @@ class Subcloud(base.Resource):
|
|||
self.systemcontroller_gateway_ip = systemcontroller_gateway_ip
|
||||
self.created_at = created_at
|
||||
self.updated_at = updated_at
|
||||
self.group_id = group_id
|
||||
self.sync_status = sync_status
|
||||
self.endpoint_sync_status = endpoint_sync_status
|
||||
|
||||
|
@ -60,32 +63,40 @@ class Subcloud(base.Resource):
|
|||
class subcloud_manager(base.ResourceManager):
|
||||
resource_class = Subcloud
|
||||
|
||||
def subcloud_create(self, url, data):
|
||||
data = json.dumps(data)
|
||||
resp = self.http_client.post(url, data)
|
||||
def json_to_resource(self, json_object):
|
||||
return self.resource_class(
|
||||
self,
|
||||
subcloud_id=json_object['id'],
|
||||
name=json_object['name'],
|
||||
description=json_object['description'],
|
||||
location=json_object['location'],
|
||||
software_version=json_object['software-version'],
|
||||
management_state=json_object['management-state'],
|
||||
availability_status=json_object['availability-status'],
|
||||
deploy_status=json_object['deploy-status'],
|
||||
management_subnet=json_object['management-subnet'],
|
||||
management_start_ip=json_object['management-start-ip'],
|
||||
management_end_ip=json_object['management-end-ip'],
|
||||
management_gateway_ip=json_object['management-gateway-ip'],
|
||||
systemcontroller_gateway_ip=json_object[
|
||||
'systemcontroller-gateway-ip'],
|
||||
created_at=json_object['created-at'],
|
||||
updated_at=json_object['updated-at'],
|
||||
group_id=json_object['group_id'])
|
||||
|
||||
def subcloud_create(self, url, body, data):
|
||||
fields = dict()
|
||||
for k, v in body.items():
|
||||
fields.update({k: (v, open(v, 'rb'),)})
|
||||
fields.update(data)
|
||||
enc = MultipartEncoder(fields=fields)
|
||||
headers = {'Content-Type': enc.content_type}
|
||||
resp = self.http_client.post(url, enc, headers=headers)
|
||||
if resp.status_code != 200:
|
||||
self._raise_api_exception(resp)
|
||||
json_object = get_json(resp)
|
||||
resource = list()
|
||||
resource.append(
|
||||
self.resource_class(
|
||||
self,
|
||||
subcloud_id=json_object['id'],
|
||||
name=json_object['name'],
|
||||
description=json_object['description'],
|
||||
location=json_object['location'],
|
||||
software_version=json_object['software-version'],
|
||||
management_state=json_object['management-state'],
|
||||
availability_status=json_object['availability-status'],
|
||||
deploy_status=json_object['deploy-status'],
|
||||
management_subnet=json_object['management-subnet'],
|
||||
management_start_ip=json_object['management-start-ip'],
|
||||
management_end_ip=json_object['management-end-ip'],
|
||||
management_gateway_ip=json_object['management-gateway-ip'],
|
||||
systemcontroller_gateway_ip=json_object[
|
||||
'systemcontroller-gateway-ip'],
|
||||
created_at=json_object['created-at'],
|
||||
updated_at=json_object['updated-at']))
|
||||
resource.append(self.json_to_resource(json_object))
|
||||
return resource
|
||||
|
||||
def subcloud_update(self, url, data):
|
||||
|
@ -113,7 +124,8 @@ class subcloud_manager(base.ResourceManager):
|
|||
systemcontroller_gateway_ip=json_object[
|
||||
'systemcontroller-gateway-ip'],
|
||||
created_at=json_object['created-at'],
|
||||
updated_at=json_object['updated-at']))
|
||||
updated_at=json_object['updated-at'],
|
||||
group_id=json_object['group_id']))
|
||||
return resource
|
||||
|
||||
def subcloud_list(self, url):
|
||||
|
@ -143,6 +155,7 @@ class subcloud_manager(base.ResourceManager):
|
|||
'systemcontroller-gateway-ip'],
|
||||
created_at=json_object['created-at'],
|
||||
updated_at=json_object['updated-at'],
|
||||
group_id=json_object['group_id'],
|
||||
sync_status=json_object['sync_status'],
|
||||
endpoint_sync_status=json_object['endpoint_sync_status']))
|
||||
return resource
|
||||
|
@ -172,15 +185,17 @@ class subcloud_manager(base.ResourceManager):
|
|||
'systemcontroller-gateway-ip'],
|
||||
created_at=json_object['created-at'],
|
||||
updated_at=json_object['updated-at'],
|
||||
group_id=json_object['group_id'],
|
||||
endpoint_sync_status=json_object['endpoint_sync_status']))
|
||||
if detail is not None:
|
||||
resource[0].oam_floating_ip = json_object['oam_floating_ip']
|
||||
return resource
|
||||
|
||||
def add_subcloud(self, **kwargs):
|
||||
data = kwargs
|
||||
data = kwargs.get('data')
|
||||
files = kwargs.get('files')
|
||||
url = '/subclouds/'
|
||||
return self.subcloud_create(url, data)
|
||||
return self.subcloud_create(url, files, data)
|
||||
|
||||
def list_subclouds(self):
|
||||
url = '/subclouds/'
|
||||
|
|
|
@ -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)
|
|
@ -54,8 +54,8 @@ class ListAlarmSummary(base.DCManagerLister):
|
|||
def _get_format_function(self):
|
||||
return format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(ListAlarmSummary, self).get_parser(parsed_args)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListAlarmSummary, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
|
|
|
@ -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,130 @@
|
|||
# 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 os
|
||||
|
||||
from dcmanagerclient.commands.v1 import base
|
||||
from dcmanagerclient import exceptions
|
||||
|
||||
|
||||
def _format(subcloud_deploy=None):
|
||||
columns = (
|
||||
'deploy_playbook',
|
||||
'deploy_overrides',
|
||||
'deploy_chart'
|
||||
)
|
||||
|
||||
if subcloud_deploy:
|
||||
data = (
|
||||
subcloud_deploy.deploy_playbook,
|
||||
subcloud_deploy.deploy_overrides,
|
||||
subcloud_deploy.deploy_chart
|
||||
)
|
||||
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class SubcloudDeployUpload(base.DCManagerShowOne):
|
||||
"""Upload the subcloud deployment files"""
|
||||
|
||||
def _get_format_function(self):
|
||||
return _format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SubcloudDeployUpload, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--deploy-playbook',
|
||||
required=True,
|
||||
help='An ansible playbook to be run after the subcloud '
|
||||
'has been successfully bootstrapped. It will be run with the '
|
||||
'subcloud as the target and authentication is '
|
||||
'handled automatically. '
|
||||
'Must be a local file path'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--deploy-overrides',
|
||||
required=True,
|
||||
help='YAML file containing subcloud variables to be passed to the '
|
||||
'deploy playbook.'
|
||||
'Must be a local file path'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--deploy-chart',
|
||||
required=True,
|
||||
help='Deployment Manager helm chart to be passed to the '
|
||||
'deploy playbook.'
|
||||
'Must be a local file path'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
dcmanager_client = self.app.client_manager.subcloud_deploy_manager
|
||||
kwargs = dict()
|
||||
if not os.path.isfile(parsed_args.deploy_playbook):
|
||||
error_msg = "deploy-playbook does not exist: %s" % \
|
||||
parsed_args.deploy_playbook
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
kwargs['deploy_playbook'] = parsed_args.deploy_playbook
|
||||
|
||||
if not os.path.isfile(parsed_args.deploy_overrides):
|
||||
error_msg = "deploy-overrides does not exist: %s" % \
|
||||
parsed_args.deploy_overrides
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
kwargs['deploy_overrides'] = parsed_args.deploy_overrides
|
||||
|
||||
if not os.path.isfile(parsed_args.deploy_chart):
|
||||
error_msg = "deploy-chart does not exist: %s" % \
|
||||
parsed_args.deploy_chart
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
kwargs['deploy_chart'] = parsed_args.deploy_chart
|
||||
|
||||
try:
|
||||
return dcmanager_client.subcloud_deploy_manager.\
|
||||
subcloud_deploy_upload(**kwargs)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_msg = "Unable to upload subcloud deploy files"
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
|
||||
class SubcloudDeployShow(base.DCManagerShowOne):
|
||||
"""Show the uploaded deployment files."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return _format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SubcloudDeployShow, self).get_parser(prog_name)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
dcmanager_client = self.app.client_manager.subcloud_deploy_manager
|
||||
return dcmanager_client.subcloud_deploy_manager.subcloud_deploy_show()
|
|
@ -0,0 +1,283 @@
|
|||
# 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 osc_lib.command import command
|
||||
|
||||
from dcmanagerclient.commands.v1 import base
|
||||
from dcmanagerclient.commands.v1.subcloud_manager import detail_format
|
||||
from dcmanagerclient import exceptions
|
||||
|
||||
|
||||
def group_format(subcloud_group=None):
|
||||
columns = (
|
||||
'id',
|
||||
'name',
|
||||
'description',
|
||||
)
|
||||
|
||||
if subcloud_group:
|
||||
data = (
|
||||
subcloud_group.group_id,
|
||||
subcloud_group.name,
|
||||
subcloud_group.description,
|
||||
)
|
||||
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def detail_group_format(subcloud_group=None):
|
||||
# Include all the fields in group_format
|
||||
# plus some additional fields
|
||||
columns = (
|
||||
'id',
|
||||
'name',
|
||||
'description',
|
||||
'update apply type',
|
||||
'max parallel subclouds',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
)
|
||||
|
||||
if subcloud_group:
|
||||
data = (
|
||||
subcloud_group.group_id,
|
||||
subcloud_group.name,
|
||||
subcloud_group.description,
|
||||
subcloud_group.update_apply_type,
|
||||
subcloud_group.max_parallel_subclouds,
|
||||
subcloud_group.created_at,
|
||||
subcloud_group.updated_at,
|
||||
)
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class AddSubcloudGroup(base.DCManagerShowOne):
|
||||
"""Add a new subcloud group."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return detail_group_format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(AddSubcloudGroup, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
required=True,
|
||||
help='Name for the new subcloud group.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--description',
|
||||
required=False,
|
||||
default='No description provided',
|
||||
help='Description of new subcloud group.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--update_apply_type',
|
||||
required=False,
|
||||
default='parallel',
|
||||
help='apply type for the new subcloud group.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--max_parallel_subclouds',
|
||||
required=False,
|
||||
default=2,
|
||||
help='max parallel subclouds for the new subcloud group.'
|
||||
)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
dcmanager_client = self.app.client_manager.subcloud_group_manager
|
||||
kwargs = dict()
|
||||
|
||||
if parsed_args.name is not None:
|
||||
kwargs['name'] = parsed_args.name
|
||||
|
||||
if parsed_args.description is not None:
|
||||
kwargs['description'] = parsed_args.description
|
||||
|
||||
if parsed_args.update_apply_type is not None:
|
||||
kwargs['update_apply_type'] = parsed_args.update_apply_type
|
||||
|
||||
if parsed_args.max_parallel_subclouds is not None:
|
||||
kwargs['max_parallel_subclouds'] = \
|
||||
parsed_args.max_parallel_subclouds
|
||||
return dcmanager_client.subcloud_group_manager.add_subcloud_group(
|
||||
**kwargs)
|
||||
|
||||
|
||||
class ListSubcloudGroup(base.DCManagerLister):
|
||||
"""List subcloud groups."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return group_format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListSubcloudGroup, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
dcmanager_client = self.app.client_manager.subcloud_group_manager
|
||||
return dcmanager_client.subcloud_group_manager.list_subcloud_groups()
|
||||
|
||||
|
||||
class ListSubcloudGroupSubclouds(base.DCManagerLister):
|
||||
"""List subclouds referencing a subcloud group."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return detail_format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListSubcloudGroupSubclouds, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'group',
|
||||
help='Name or ID of subcloud group to list associated subclouds.'
|
||||
)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
subcloud_group_ref = parsed_args.group
|
||||
dcmanager_client = self.app.client_manager.subcloud_group_manager
|
||||
return dcmanager_client.subcloud_group_manager. \
|
||||
subcloud_group_list_subclouds(subcloud_group_ref)
|
||||
|
||||
|
||||
class ShowSubcloudGroup(base.DCManagerShowOne):
|
||||
"""Show the details of a subcloud group."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return detail_group_format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowSubcloudGroup, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'group',
|
||||
help='Name or ID of subcloud group to view the details.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
subcloud_group_ref = parsed_args.group
|
||||
dcmanager_client = self.app.client_manager.subcloud_group_manager
|
||||
return dcmanager_client.subcloud_group_manager.\
|
||||
subcloud_group_detail(subcloud_group_ref)
|
||||
|
||||
|
||||
class DeleteSubcloudGroup(command.Command):
|
||||
"""Delete subcloud group details from the database."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteSubcloudGroup, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'group',
|
||||
help='Name or ID of the subcloud group to delete.'
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
subcloud_group_ref = parsed_args.group
|
||||
dcmanager_client = self.app.client_manager.subcloud_group_manager
|
||||
try:
|
||||
dcmanager_client.subcloud_group_manager.\
|
||||
delete_subcloud_group(subcloud_group_ref)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
msg = "Unable to delete subcloud group %s" % (subcloud_group_ref)
|
||||
raise exceptions.DCManagerClientException(msg)
|
||||
|
||||
|
||||
class UpdateSubcloudGroup(base.DCManagerShowOne):
|
||||
"""Update attributes of a subcloud group."""
|
||||
|
||||
def _get_format_function(self):
|
||||
return detail_group_format
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateSubcloudGroup, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'group',
|
||||
help='Name or ID of the subcloud group to update.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
required=False,
|
||||
help='Name of subcloud group.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--description',
|
||||
required=False,
|
||||
help='Description of subcloud group.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--update_apply_type',
|
||||
required=False,
|
||||
help='Update apply type of subcloud group.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--max_parallel_subclouds',
|
||||
type=int,
|
||||
required=False,
|
||||
help='max parallel subclouds of subcloud group.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
subcloud_group_ref = parsed_args.group
|
||||
dcmanager_client = self.app.client_manager.subcloud_group_manager
|
||||
kwargs = dict()
|
||||
if parsed_args.name:
|
||||
kwargs['name'] = parsed_args.name
|
||||
if parsed_args.description:
|
||||
kwargs['description'] = parsed_args.description
|
||||
if parsed_args.update_apply_type:
|
||||
kwargs['update_apply_type'] = parsed_args.update_apply_type
|
||||
if parsed_args.max_parallel_subclouds:
|
||||
kwargs['max_parallel_subclouds'] = \
|
||||
parsed_args.max_parallel_subclouds
|
||||
if len(kwargs) == 0:
|
||||
error_msg = "Nothing to update"
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
||||
try:
|
||||
return dcmanager_client. \
|
||||
subcloud_group_manager.update_subcloud_group(
|
||||
subcloud_group_ref, **kwargs)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
msg = "Unable to update subcloud group %s" % (subcloud_group_ref)
|
||||
raise exceptions.DCManagerClientException(msg)
|
|
@ -19,15 +19,14 @@
|
|||
# of an applicable Wind River license agreement.
|
||||
#
|
||||
|
||||
import base64
|
||||
import getpass
|
||||
import os
|
||||
import yaml
|
||||
|
||||
from osc_lib.command import command
|
||||
|
||||
from dcmanagerclient.commands.v1 import base
|
||||
from dcmanagerclient import exceptions
|
||||
from dcmanagerclient import utils
|
||||
|
||||
|
||||
def format(subcloud=None):
|
||||
|
@ -71,6 +70,7 @@ def detail_format(subcloud=None):
|
|||
'management_end_ip',
|
||||
'management_gateway_ip',
|
||||
'systemcontroller_gateway_ip',
|
||||
'group_id',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
)
|
||||
|
@ -90,6 +90,7 @@ def detail_format(subcloud=None):
|
|||
subcloud.management_end_ip,
|
||||
subcloud.management_gateway_ip,
|
||||
subcloud.systemcontroller_gateway_ip,
|
||||
subcloud.group_id,
|
||||
subcloud.created_at,
|
||||
subcloud.updated_at,
|
||||
)
|
||||
|
@ -117,8 +118,8 @@ class AddSubcloud(base.DCManagerShowOne):
|
|||
def _get_format_function(self):
|
||||
return detail_format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(AddSubcloud, self).get_parser(parsed_args)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(AddSubcloud, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--bootstrap-address',
|
||||
|
@ -134,17 +135,7 @@ class AddSubcloud(base.DCManagerShowOne):
|
|||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--deploy-playbook',
|
||||
required=False,
|
||||
help='An optional ansible playbook to be run after the subcloud '
|
||||
'has been successfully bootstrapped. It will be run with the '
|
||||
'subcloud as the target and authentication is '
|
||||
'handled automatically. '
|
||||
'Can be either a local file path or a URL.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--deploy-values',
|
||||
'--deploy-config',
|
||||
required=False,
|
||||
help='YAML file containing subcloud variables to be passed to the '
|
||||
'deploy playbook.'
|
||||
|
@ -170,56 +161,47 @@ class AddSubcloud(base.DCManagerShowOne):
|
|||
help='bmc password of the subcloud to be configured, '
|
||||
'if not provided you will be prompted.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--group',
|
||||
required=False,
|
||||
help='Name or ID of subcloud group.'
|
||||
)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
dcmanager_client = self.app.client_manager.subcloud_manager
|
||||
kwargs = dict()
|
||||
kwargs['bootstrap-address'] = parsed_args.bootstrap_address
|
||||
files = dict()
|
||||
data = dict()
|
||||
data['bootstrap-address'] = parsed_args.bootstrap_address
|
||||
|
||||
# Load the configuration from the install values yaml file
|
||||
# Get the install values yaml file
|
||||
if parsed_args.install_values is not None:
|
||||
filename = parsed_args.install_values
|
||||
stream = utils.get_contents_if_file(filename)
|
||||
kwargs['install_values'] = yaml.safe_load(stream)
|
||||
|
||||
# Load the configuration from the bootstrap yaml file
|
||||
filename = parsed_args.bootstrap_values
|
||||
stream = utils.get_contents_if_file(filename)
|
||||
kwargs.update(yaml.safe_load(stream))
|
||||
|
||||
# Load the the deploy playbook yaml file
|
||||
if parsed_args.deploy_playbook is not None:
|
||||
if parsed_args.deploy_values is None:
|
||||
error_msg = "Error: Deploy playbook cannot be specified " \
|
||||
"when the deploy values file has not been " \
|
||||
"specified."
|
||||
if not os.path.isfile(parsed_args.install_values):
|
||||
error_msg = "install-values does not exist: %s" % \
|
||||
parsed_args.install_values
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
filename = parsed_args.deploy_playbook
|
||||
stream = utils.get_contents_if_file(filename)
|
||||
kwargs['deploy_playbook'] = yaml.safe_load(stream)
|
||||
files['install_values'] = parsed_args.install_values
|
||||
|
||||
# Load the configuration from the deploy values yaml file
|
||||
if parsed_args.deploy_values is not None:
|
||||
if parsed_args.deploy_playbook is None:
|
||||
error_msg = "Error: Deploy values cannot be specified " \
|
||||
"when a deploy playbook has not been specified."
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
# Get the bootstrap values yaml file
|
||||
if not os.path.isfile(parsed_args.bootstrap_values):
|
||||
error_msg = "bootstrap-values does not exist: %s" % \
|
||||
parsed_args.bootstrap_values
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
files['bootstrap_values'] = parsed_args.bootstrap_values
|
||||
|
||||
filename = parsed_args.deploy_values
|
||||
if os.path.isdir(filename):
|
||||
error_msg = "Error: %s is a directory." % filename
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
try:
|
||||
with open(filename, 'rb') as stream:
|
||||
kwargs['deploy_values'] = yaml.safe_load(stream)
|
||||
except Exception:
|
||||
error_msg = "Error: Could not open file %s." % filename
|
||||
# Get the deploy config yaml file
|
||||
if parsed_args.deploy_config is not None:
|
||||
if not os.path.isfile(parsed_args.deploy_config):
|
||||
error_msg = "deploy-config does not exist: %s" % \
|
||||
parsed_args.deploy_config
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
files['deploy_config'] = parsed_args.deploy_config
|
||||
|
||||
# Prompt the user for the subcloud's password if it isn't provided
|
||||
if parsed_args.sysadmin_password is not None:
|
||||
kwargs['sysadmin_password'] = parsed_args.sysadmin_password
|
||||
data['sysadmin_password'] = base64.b64encode(
|
||||
parsed_args.sysadmin_password.encode("utf-8"))
|
||||
else:
|
||||
while True:
|
||||
password = getpass.getpass(
|
||||
|
@ -233,12 +215,14 @@ class AddSubcloud(base.DCManagerShowOne):
|
|||
if password != confirm:
|
||||
print("Passwords did not match")
|
||||
continue
|
||||
kwargs["sysadmin_password"] = password
|
||||
data["sysadmin_password"] = base64.b64encode(
|
||||
password.encode("utf-8"))
|
||||
break
|
||||
|
||||
if parsed_args.install_values is not None:
|
||||
if parsed_args.bmc_password is not None:
|
||||
kwargs['bmc_password'] = parsed_args.bmc_password
|
||||
data['bmc_password'] = base64.b64encode(
|
||||
parsed_args.bmc_password.encode("utf-8"))
|
||||
else:
|
||||
while True:
|
||||
password = getpass.getpass(
|
||||
|
@ -252,10 +236,15 @@ class AddSubcloud(base.DCManagerShowOne):
|
|||
if password != confirm:
|
||||
print("Passwords did not match")
|
||||
continue
|
||||
kwargs["bmc_password"] = password
|
||||
data["bmc_password"] = base64.b64encode(
|
||||
password.encode("utf-8"))
|
||||
break
|
||||
|
||||
return dcmanager_client.subcloud_manager.add_subcloud(**kwargs)
|
||||
if parsed_args.group is not None:
|
||||
data['group_id'] = parsed_args.group
|
||||
|
||||
return dcmanager_client.subcloud_manager.add_subcloud(files=files,
|
||||
data=data)
|
||||
|
||||
|
||||
class ListSubcloud(base.DCManagerLister):
|
||||
|
@ -264,8 +253,8 @@ class ListSubcloud(base.DCManagerLister):
|
|||
def _get_format_function(self):
|
||||
return format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(ListSubcloud, self).get_parser(parsed_args)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListSubcloud, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
|
@ -279,8 +268,8 @@ class ShowSubcloud(base.DCManagerShowOne):
|
|||
def _get_format_function(self):
|
||||
return detail_format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(ShowSubcloud, self).get_parser(parsed_args)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowSubcloud, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'subcloud',
|
||||
|
@ -413,6 +402,12 @@ class UpdateSubcloud(base.DCManagerShowOne):
|
|||
help='Location of subcloud.'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--group',
|
||||
required=False,
|
||||
help='Name or ID of subcloud group.'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
|
@ -423,6 +418,8 @@ class UpdateSubcloud(base.DCManagerShowOne):
|
|||
kwargs['description'] = parsed_args.description
|
||||
if parsed_args.location:
|
||||
kwargs['location'] = parsed_args.location
|
||||
if parsed_args.group:
|
||||
kwargs['group_id'] = parsed_args.group
|
||||
if len(kwargs) == 0:
|
||||
error_msg = "Nothing to update"
|
||||
raise exceptions.DCManagerClientException(error_msg)
|
||||
|
|
|
@ -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, parsed_args):
|
||||
parser = super(CreatePatchStrategy, self).get_parser(parsed_args)
|
||||
def get_parser(self, 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, parsed_args):
|
||||
parser = super(ShowPatchStrategy, self).get_parser(parsed_args)
|
||||
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, parsed_args):
|
||||
parser = super(ListStrategyStep, self).get_parser(parsed_args)
|
||||
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, parsed_args):
|
||||
parser = super(ShowStrategyStep, self).get_parser(parsed_args)
|
||||
def get_parser(self, 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)
|
||||
|
|
|
@ -89,8 +89,8 @@ class UpdateSwUpdateOptions(base.DCManagerShowOne):
|
|||
def _get_format_function(self):
|
||||
return options_detail_format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(UpdateSwUpdateOptions, self).get_parser(parsed_args)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateSwUpdateOptions, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--storage-apply-type',
|
||||
|
@ -163,8 +163,8 @@ class ListSwUpdateOptions(base.DCManagerLister):
|
|||
def _get_format_function(self):
|
||||
return options_list_format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(ListSwUpdateOptions, self).get_parser(parsed_args)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListSwUpdateOptions, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def _get_resources(self, parsed_args):
|
||||
|
@ -179,8 +179,8 @@ class ShowSwUpdateOptions(base.DCManagerShowOne):
|
|||
def _get_format_function(self):
|
||||
return options_detail_format
|
||||
|
||||
def get_parser(self, parsed_args):
|
||||
parser = super(ShowSwUpdateOptions, self).get_parser(parsed_args)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowSwUpdateOptions, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'subcloud',
|
||||
|
|
|
@ -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
|
|
@ -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) 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
|
||||
|
@ -37,9 +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__)
|
||||
|
||||
|
@ -444,10 +449,14 @@ class DCManagerShell(app.App):
|
|||
'ClientManager',
|
||||
(object,),
|
||||
dict(subcloud_manager=self.client,
|
||||
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()
|
||||
|
||||
|
@ -480,18 +489,40 @@ class DCManagerShell(app.App):
|
|||
'subcloud unmanage': sm.UnmanageSubcloud,
|
||||
'subcloud manage': sm.ManageSubcloud,
|
||||
'subcloud update': sm.UpdateSubcloud,
|
||||
'subcloud-group add': gm.AddSubcloudGroup,
|
||||
'subcloud-group delete': gm.DeleteSubcloudGroup,
|
||||
'subcloud-group list': gm.ListSubcloudGroup,
|
||||
'subcloud-group list-subclouds': gm.ListSubcloudGroupSubclouds,
|
||||
'subcloud-group show': gm.ShowSubcloudGroup,
|
||||
'subcloud-group update': gm.UpdateSubcloudGroup,
|
||||
'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,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ class FakeResponse(object):
|
|||
self.status_code = status_code
|
||||
self.content = content
|
||||
self.headers = {}
|
||||
self.text = ''
|
||||
|
||||
def json(self):
|
||||
return json.loads(self.content)
|
||||
|
|
|
@ -70,6 +70,7 @@ class FakeResponse(object):
|
|||
self.request = FakeRequest(method)
|
||||
self.url = url
|
||||
self.status_code = status_code
|
||||
self.text = ''
|
||||
|
||||
|
||||
class HTTPClientTest(testtools.TestCase):
|
||||
|
|
|
@ -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])
|
|
@ -0,0 +1,83 @@
|
|||
# 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 os
|
||||
import tempfile
|
||||
|
||||
from dcmanagerclient.api.v1 import subcloud_deploy_manager as sdm
|
||||
from dcmanagerclient.commands.v1 \
|
||||
import subcloud_deploy_manager as subcloud_deploy_cmd
|
||||
from dcmanagerclient.tests import base
|
||||
|
||||
|
||||
DEPLOY_PLAYBOOK = 'deployment-manager-playbook.yaml'
|
||||
DEPLOY_OVERRIDES = 'deployment-manager-overrides-subcloud.yaml'
|
||||
DEPLOY_CHART = 'deployment-manager.tgz'
|
||||
|
||||
SUBCLOUD_DEPLOY_DICT = {
|
||||
'DEPLOY_PLAYBOOK': DEPLOY_PLAYBOOK,
|
||||
'DEPLOY_OVERRIDES': DEPLOY_OVERRIDES,
|
||||
'DEPLOY_CHART': DEPLOY_CHART
|
||||
}
|
||||
|
||||
SUBCLOUD_DEPLOY = sdm.SubcloudDeploy(
|
||||
deploy_playbook=SUBCLOUD_DEPLOY_DICT['DEPLOY_PLAYBOOK'],
|
||||
deploy_overrides=SUBCLOUD_DEPLOY_DICT['DEPLOY_OVERRIDES'],
|
||||
deploy_chart=SUBCLOUD_DEPLOY_DICT['DEPLOY_CHART']
|
||||
)
|
||||
|
||||
|
||||
class TestCLISubcloudDeployManagerV1(base.BaseCommandTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCLISubcloudDeployManagerV1, self).setUp()
|
||||
# The client is the subcloud_deploy_manager
|
||||
self.client = self.app.client_manager.subcloud_deploy_manager
|
||||
|
||||
def test_subcloud_deploy_show(self):
|
||||
self.client.subcloud_deploy_manager.subcloud_deploy_show.\
|
||||
return_value = [SUBCLOUD_DEPLOY]
|
||||
actual_call = self.call(subcloud_deploy_cmd.SubcloudDeployShow)
|
||||
|
||||
self.assertEqual((DEPLOY_PLAYBOOK,
|
||||
DEPLOY_OVERRIDES,
|
||||
DEPLOY_CHART),
|
||||
actual_call[1])
|
||||
|
||||
def test_subcloud_deploy_upload(self):
|
||||
self.client.subcloud_deploy_manager.subcloud_deploy_upload.\
|
||||
return_value = [SUBCLOUD_DEPLOY]
|
||||
|
||||
with tempfile.NamedTemporaryFile() as f1,\
|
||||
tempfile.NamedTemporaryFile() as f2,\
|
||||
tempfile.NamedTemporaryFile() as f3:
|
||||
file_path_1 = os.path.abspath(f1.name)
|
||||
file_path_2 = os.path.abspath(f2.name)
|
||||
file_path_3 = os.path.abspath(f3.name)
|
||||
actual_call = self.call(
|
||||
subcloud_deploy_cmd.SubcloudDeployUpload,
|
||||
app_args=[
|
||||
'--deploy-playbook', file_path_1,
|
||||
'--deploy-overrides', file_path_2,
|
||||
'--deploy-chart', file_path_3])
|
||||
|
||||
self.assertEqual((DEPLOY_PLAYBOOK,
|
||||
DEPLOY_OVERRIDES,
|
||||
DEPLOY_CHART),
|
||||
actual_call[1])
|
|
@ -0,0 +1,161 @@
|
|||
# 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.
|
||||
#
|
||||
|
||||
import copy
|
||||
import mock
|
||||
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from dcmanagerclient.api.v1 import subcloud_group_manager as zm
|
||||
from dcmanagerclient.commands.v1 \
|
||||
import subcloud_group_manager as subcloud_group_cmd
|
||||
from dcmanagerclient.tests import base
|
||||
from dcmanagerclient.tests.v1 import test_subcloud_manager as tsm
|
||||
|
||||
|
||||
ID = '2'
|
||||
NAME = 'GroupX'
|
||||
DESCRIPTION = 'Custom subcloud group'
|
||||
APPLY_TYPE = 'parallel'
|
||||
MAX_PARALLEL_SUBCLOUDS = 3
|
||||
TIME_NOW = timeutils.utcnow().isoformat()
|
||||
NEW_DESCRIPTION = 'Slightly different subcloud group'
|
||||
|
||||
SUBCLOUD_GROUP_DICT = {
|
||||
'GROUP_ID': ID,
|
||||
'NAME': NAME,
|
||||
'DESCRIPTION': DESCRIPTION,
|
||||
'APPLY_TYPE': APPLY_TYPE,
|
||||
'MAX_PARALLEL_SUBCLOUDS': MAX_PARALLEL_SUBCLOUDS,
|
||||
'CREATED_AT': TIME_NOW,
|
||||
'UPDATED_AT': TIME_NOW
|
||||
}
|
||||
|
||||
SUBCLOUD_GROUP = zm.SubcloudGroup(
|
||||
mock,
|
||||
group_id=SUBCLOUD_GROUP_DICT['GROUP_ID'],
|
||||
name=SUBCLOUD_GROUP_DICT['NAME'],
|
||||
description=SUBCLOUD_GROUP_DICT['DESCRIPTION'],
|
||||
update_apply_type=SUBCLOUD_GROUP_DICT['APPLY_TYPE'],
|
||||
max_parallel_subclouds=SUBCLOUD_GROUP_DICT['MAX_PARALLEL_SUBCLOUDS'],
|
||||
created_at=SUBCLOUD_GROUP_DICT['CREATED_AT'],
|
||||
updated_at=SUBCLOUD_GROUP_DICT['UPDATED_AT']
|
||||
)
|
||||
|
||||
|
||||
class TestCLISubcloudGroupManagerV1(base.BaseCommandTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCLISubcloudGroupManagerV1, self).setUp()
|
||||
# The client is the subcloud_group_manager
|
||||
self.client = self.app.client_manager.subcloud_group_manager
|
||||
|
||||
def test_list_subcloud_groups(self):
|
||||
self.client.subcloud_group_manager.\
|
||||
list_subcloud_groups.return_value = [SUBCLOUD_GROUP]
|
||||
actual_call = self.call(subcloud_group_cmd.ListSubcloudGroup)
|
||||
self.assertEqual([(ID, NAME, DESCRIPTION)],
|
||||
actual_call[1])
|
||||
|
||||
def test_list_subcloud_groups_empty(self):
|
||||
self.client.subcloud_group_manager.\
|
||||
list_subcloud_groups.return_value = []
|
||||
actual_call = self.call(subcloud_group_cmd.ListSubcloudGroup)
|
||||
self.assertEqual((('<none>', '<none>', '<none>'),),
|
||||
actual_call[1])
|
||||
|
||||
def test_list_subcloud_group_subclouds(self):
|
||||
self.client.subcloud_group_manager.\
|
||||
subcloud_group_list_subclouds.return_value = [tsm.SUBCLOUD]
|
||||
actual_call = self.call(subcloud_group_cmd.ListSubcloudGroupSubclouds,
|
||||
app_args=[ID])
|
||||
self.client.subcloud_group_manager.subcloud_group_list_subclouds.\
|
||||
assert_called_once_with(ID)
|
||||
self.assertEqual([tsm.DEFAULT_SUBCLOUD_FIELD_RESULT_LIST],
|
||||
actual_call[1])
|
||||
|
||||
def test_delete_subcloud_group_by_id(self):
|
||||
self.call(subcloud_group_cmd.DeleteSubcloudGroup, app_args=[ID])
|
||||
self.client.subcloud_group_manager.delete_subcloud_group.\
|
||||
assert_called_once_with(ID)
|
||||
|
||||
def test_delete_subcloud_group_without_id(self):
|
||||
self.assertRaises(SystemExit, self.call,
|
||||
subcloud_group_cmd.DeleteSubcloudGroup, app_args=[])
|
||||
|
||||
def test_show_subcloud_group_with_id(self):
|
||||
self.client.subcloud_group_manager.subcloud_group_detail.\
|
||||
return_value = [SUBCLOUD_GROUP]
|
||||
actual_call = self.call(subcloud_group_cmd.ShowSubcloudGroup,
|
||||
app_args=[ID])
|
||||
self.assertEqual((ID,
|
||||
NAME,
|
||||
DESCRIPTION,
|
||||
APPLY_TYPE,
|
||||
MAX_PARALLEL_SUBCLOUDS,
|
||||
TIME_NOW,
|
||||
TIME_NOW),
|
||||
actual_call[1])
|
||||
|
||||
def test_show_subcloud_group_without_id(self):
|
||||
self.client.subcloud_group_manager.subcloud_group_detail.\
|
||||
return_value = []
|
||||
actual_call = self.call(subcloud_group_cmd.ShowSubcloudGroup,
|
||||
app_args=[ID])
|
||||
self.assertEqual((('<none>', '<none>', '<none>', '<none>',
|
||||
'<none>', '<none>', '<none>'),),
|
||||
actual_call[1])
|
||||
|
||||
def test_add_subcloud_group(self):
|
||||
self.client.subcloud_group_manager.add_subcloud_group.\
|
||||
return_value = [SUBCLOUD_GROUP]
|
||||
|
||||
actual_call = self.call(
|
||||
subcloud_group_cmd.AddSubcloudGroup,
|
||||
app_args=['--name', NAME,
|
||||
'--description', DESCRIPTION]
|
||||
)
|
||||
self.assertEqual((ID,
|
||||
NAME,
|
||||
DESCRIPTION,
|
||||
APPLY_TYPE,
|
||||
MAX_PARALLEL_SUBCLOUDS,
|
||||
TIME_NOW,
|
||||
TIME_NOW),
|
||||
actual_call[1])
|
||||
|
||||
def test_update_subcloud_group(self):
|
||||
UPDATED_SUBCLOUD = copy.copy(SUBCLOUD_GROUP)
|
||||
UPDATED_SUBCLOUD.description = NEW_DESCRIPTION
|
||||
self.client.subcloud_group_manager.update_subcloud_group.\
|
||||
return_value = [UPDATED_SUBCLOUD]
|
||||
actual_call = self.call(
|
||||
subcloud_group_cmd.UpdateSubcloudGroup,
|
||||
app_args=[SUBCLOUD_GROUP.group_id,
|
||||
'--description', NEW_DESCRIPTION])
|
||||
self.assertEqual((ID,
|
||||
NAME,
|
||||
NEW_DESCRIPTION,
|
||||
APPLY_TYPE,
|
||||
MAX_PARALLEL_SUBCLOUDS,
|
||||
TIME_NOW,
|
||||
TIME_NOW),
|
||||
actual_call[1])
|
|
@ -51,6 +51,7 @@ SYSTEMCONTROLLER_GATEWAY_IP = '192.168.204.101'
|
|||
EXTERNAL_OAM_SUBNET = "10.10.10.0/24"
|
||||
EXTERNAL_OAM_GATEWAY_ADDRESS = "10.10.10.1"
|
||||
EXTERNAL_OAM_FLOATING_ADDRESS = "10.10.10.12"
|
||||
DEFAULT_SUBCLOUD_GROUP_ID = '1'
|
||||
|
||||
SUBCLOUD_DICT = {
|
||||
'SUBCLOUD_ID': ID,
|
||||
|
@ -68,6 +69,7 @@ SUBCLOUD_DICT = {
|
|||
'SYSTEMCONTROLLER_GATEWAY_IP': SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
'CREATED_AT': TIME_NOW,
|
||||
'UPDATED_AT': TIME_NOW,
|
||||
'GROUP_ID': DEFAULT_SUBCLOUD_GROUP_ID,
|
||||
'OAM_FLOATING_IP': EXTERNAL_OAM_FLOATING_ADDRESS
|
||||
}
|
||||
|
||||
|
@ -87,7 +89,26 @@ SUBCLOUD = sm.Subcloud(
|
|||
management_gateway_ip=SUBCLOUD_DICT['MANAGEMENT_GATEWAY_IP'],
|
||||
systemcontroller_gateway_ip=SUBCLOUD_DICT['SYSTEMCONTROLLER_GATEWAY_IP'],
|
||||
created_at=SUBCLOUD_DICT['CREATED_AT'],
|
||||
updated_at=SUBCLOUD_DICT['UPDATED_AT'])
|
||||
updated_at=SUBCLOUD_DICT['UPDATED_AT'],
|
||||
group_id=SUBCLOUD_DICT['GROUP_ID'])
|
||||
|
||||
DEFAULT_SUBCLOUD_FIELD_RESULT_LIST = (
|
||||
ID,
|
||||
NAME,
|
||||
DESCRIPTION,
|
||||
LOCATION,
|
||||
SOFTWARE_VERSION,
|
||||
MANAGEMENT_STATE,
|
||||
AVAILABILITY_STATUS,
|
||||
DEPLOY_STATUS,
|
||||
MANAGEMENT_SUBNET,
|
||||
MANAGEMENT_START_IP,
|
||||
MANAGEMENT_END_IP,
|
||||
MANAGEMENT_GATEWAY_IP,
|
||||
SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
DEFAULT_SUBCLOUD_GROUP_ID,
|
||||
TIME_NOW,
|
||||
TIME_NOW)
|
||||
|
||||
|
||||
class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
||||
|
@ -119,19 +140,7 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
self.client.subcloud_manager.subcloud_detail.\
|
||||
return_value = [SUBCLOUD]
|
||||
actual_call = self.call(subcloud_cmd.ShowSubcloud, app_args=[ID])
|
||||
self.assertEqual((ID, NAME,
|
||||
DESCRIPTION,
|
||||
LOCATION,
|
||||
SOFTWARE_VERSION,
|
||||
MANAGEMENT_STATE,
|
||||
AVAILABILITY_STATUS,
|
||||
DEPLOY_STATUS,
|
||||
MANAGEMENT_SUBNET,
|
||||
MANAGEMENT_START_IP,
|
||||
MANAGEMENT_END_IP,
|
||||
MANAGEMENT_GATEWAY_IP,
|
||||
SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
TIME_NOW, TIME_NOW),
|
||||
self.assertEqual(DEFAULT_SUBCLOUD_FIELD_RESULT_LIST,
|
||||
actual_call[1])
|
||||
|
||||
def test_show_subcloud_with_additional_detail(self):
|
||||
|
@ -155,6 +164,7 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
MANAGEMENT_END_IP,
|
||||
MANAGEMENT_GATEWAY_IP,
|
||||
SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
DEFAULT_SUBCLOUD_GROUP_ID,
|
||||
TIME_NOW, TIME_NOW,
|
||||
EXTERNAL_OAM_FLOATING_ADDRESS),
|
||||
actual_call[1])
|
||||
|
@ -165,7 +175,7 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
self.assertEqual((('<none>', '<none>', '<none>', '<none>',
|
||||
'<none>', '<none>', '<none>', '<none>',
|
||||
'<none>', '<none>', '<none>', '<none>',
|
||||
'<none>', '<none>', '<none>'),),
|
||||
'<none>', '<none>', '<none>', '<none>'),),
|
||||
actual_call[1])
|
||||
|
||||
@mock.patch('getpass.getpass', return_value='testpassword')
|
||||
|
@ -200,6 +210,7 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
MANAGEMENT_SUBNET, MANAGEMENT_START_IP,
|
||||
MANAGEMENT_END_IP, MANAGEMENT_GATEWAY_IP,
|
||||
SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
DEFAULT_SUBCLOUD_GROUP_ID,
|
||||
TIME_NOW, TIME_NOW), actual_call[1])
|
||||
|
||||
def test_unmanage_subcloud(self):
|
||||
|
@ -214,6 +225,7 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
MANAGEMENT_SUBNET, MANAGEMENT_START_IP,
|
||||
MANAGEMENT_END_IP, MANAGEMENT_GATEWAY_IP,
|
||||
SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
DEFAULT_SUBCLOUD_GROUP_ID,
|
||||
TIME_NOW, TIME_NOW), actual_call[1])
|
||||
|
||||
def test_unmanage_subcloud_without_subcloud_id(self):
|
||||
|
@ -232,6 +244,7 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
MANAGEMENT_SUBNET, MANAGEMENT_START_IP,
|
||||
MANAGEMENT_END_IP, MANAGEMENT_GATEWAY_IP,
|
||||
SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
DEFAULT_SUBCLOUD_GROUP_ID,
|
||||
TIME_NOW, TIME_NOW), actual_call[1])
|
||||
|
||||
def test_manage_subcloud_without_subcloud_id(self):
|
||||
|
@ -253,4 +266,5 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest):
|
|||
MANAGEMENT_SUBNET, MANAGEMENT_START_IP,
|
||||
MANAGEMENT_END_IP, MANAGEMENT_GATEWAY_IP,
|
||||
SYSTEMCONTROLLER_GATEWAY_IP,
|
||||
DEFAULT_SUBCLOUD_GROUP_ID,
|
||||
TIME_NOW, TIME_NOW), actual_call[1])
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
[MASTER]
|
||||
# Specify a configuration file.
|
||||
rcfile=pylint.rc
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code.
|
||||
extension-pkg-whitelist=greenlet
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not paths.
|
||||
ignore=tests
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
#enable=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once).
|
||||
# http://pylint.pycqa.org/en/latest/technical_reference/features.html
|
||||
#
|
||||
# fixme: warning note, todo, etc..
|
||||
# R detect Refactor for a "good practice" metric violation
|
||||
# C detect Convention for coding standard violation
|
||||
# W0102: dangerous-default-value
|
||||
# W0201: attribute-defined-outside-init
|
||||
# W0212: protected-access
|
||||
# W0231: super-init-not-called
|
||||
# W0403: relative-import (typically caused by six)
|
||||
# W0603: global-statement
|
||||
# W0612: unused-variable
|
||||
# W0613: unused-argument
|
||||
# W0621: redefined-outer-name
|
||||
# W0622: redefined-builtin
|
||||
# W0703: broad-except
|
||||
# W1201: logging-not-lazy
|
||||
# W1113: keyword-arg-before-vararg
|
||||
# E1102: not-callable
|
||||
disable=fixme,C,R,
|
||||
W0102,W0201,W0212,W0231,W0403,
|
||||
W0612,W0613,W0603,W0621,W0622,W0703,W1201,W1113,
|
||||
E1102
|
||||
|
||||
[REPORTS]
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html
|
||||
output-format=text
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]".
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
|
||||
[FORMAT]
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=85
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 tab).
|
||||
indent-string=' '
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis
|
||||
ignored-modules=distutils,eventlet.green.subprocess,six,six.moves
|
||||
|
||||
# List of classes names for which member attributes should not be checked
|
||||
# (useful for classes with attributes dynamically set).
|
||||
# pylint is confused by sqlalchemy Table, as well as sqlalchemy Enum types
|
||||
ignored-classes=SQLObject,Table
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E0201 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=REQUEST,acl_users,aq_parent
|
||||
|
||||
|
||||
[BASIC]
|
||||
# List of builtins function names that should not be used, separated by a comma
|
||||
bad-functions=map,filter,apply,input
|
||||
|
||||
# Regular expression which should only match correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression which should only match correct module level names
|
||||
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression which should only match correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression which should only match correct function names
|
||||
function-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct method names
|
||||
method-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct instance attribute names
|
||||
attr-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct argument names
|
||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct variable names
|
||||
variable-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct list comprehension /
|
||||
# generator expression variable names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,j,k,ex,Run,_
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
# Regular expression which should only match functions or classes name which do
|
||||
# not require a docstring
|
||||
no-docstring-rgx=__.*__
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching the beginning of the name of dummy variables
|
||||
# (i.e. not used).
|
||||
dummy-variables-rgx=_|dummy
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
|
||||
[DESIGN]
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branchs=12
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
|
||||
[CLASSES]
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=Exception
|
|
@ -10,3 +10,4 @@ PyYAML>=3.10.0 # MIT
|
|||
requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
beautifulsoup4
|
||||
requests-toolbelt
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
|
||||
pylint==1.4.5 # GPLv2
|
||||
pylint==1.9.2;python_version<"3.0" # GPLv2
|
||||
pylint==2.3.1;python_version>="3.0" # GPLv2
|
||||
python-openstackclient>=3.3.0 # Apache-2.0
|
||||
sphinx>=1.5.1 # BSD
|
||||
unittest2 # BSD
|
||||
|
@ -11,6 +12,5 @@ mock>=2.0 # BSD
|
|||
nose # LGPL
|
||||
tempest>=14.0.0 # Apache-2.0
|
||||
testtools>=1.4.0 # MIT
|
||||
|
||||
PyYAML>=3.1.0
|
||||
yamllint>=0.5.2
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[tox]
|
||||
minversion = 2.3
|
||||
envlist = py27,pep8
|
||||
envlist = py27,pep8,pylint
|
||||
skipsdist = True
|
||||
|
||||
toxworkdir = /tmp/{env:USER}_dc_client_tox
|
||||
|
@ -36,6 +36,13 @@ commands =
|
|||
basepython = python3
|
||||
commands = flake8 {posargs}
|
||||
|
||||
[testenv:pylint]
|
||||
basepython = python2.7
|
||||
sitepackages = False
|
||||
deps = {[testenv]deps}
|
||||
commands =
|
||||
pylint {posargs} dcmanagerclient --rcfile=./pylint.rc
|
||||
|
||||
[testenv:venv]
|
||||
basepython = python3
|
||||
commands = {posargs}
|
||||
|
|
Loading…
Reference in New Issue