Release repos list/update

Fuel releases contain metadata including default
set of rpm/deb repositories that are to be used
during cluster deployment. This change introduces
couple new subcommands that allow to view and change
the list of release repositories.

DocImpact
Change-Id: Ied9d69b98345318d7a92ca4c7093ac0424599cc3
Implements: blueprint fuelclient-modify-release-repos
This commit is contained in:
Vladimir Kozhukalov
2016-06-07 15:46:51 +03:00
committed by Roman Prykhodchenko
parent 34b745f54a
commit 5b2b85d93d
9 changed files with 258 additions and 0 deletions

View File

@@ -71,6 +71,7 @@ def get_client(resource, version='v1', connection=None):
'node': v1.node,
'openstack-config': v1.openstack_config,
'plugins': v1.plugins,
'release': v1.release,
'task': v1.task,
'vip': v1.vip
}

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Mirantis, Inc.
#
# 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.
from fuelclient.commands import base
from fuelclient.common import data_utils
from fuelclient import utils
class ReleaseMixIn(object):
entity_name = 'release'
class ReleaseList(ReleaseMixIn, base.BaseListCommand):
"""Show list of all available releases."""
columns = ("id",
"name",
"state",
"operating_system",
"version")
class ReleaseReposList(ReleaseMixIn, base.BaseListCommand):
"""Show repos for a given release."""
def columns(self, repos):
if repos:
return tuple(repos[0])
return ()
def get_parser(self, prog_name):
parser = super(ReleaseReposList, self).get_parser(prog_name)
parser.add_argument('id', type=int,
help='Id of the {0}.'.format(self.entity_name))
return parser
def take_action(self, parsed_args):
data = self.client.get_attributes_metadata_by_id(parsed_args.id)
repos = data["editable"]["repo_setup"]["repos"]["value"]
columns = self.columns(repos)
repos = data_utils.get_display_data_multi(columns, repos)
return columns, repos
class ReleaseReposUpdate(ReleaseMixIn, base.BaseCommand):
"""Update repos for a given release."""
def get_parser(self, prog_name):
parser = super(ReleaseReposUpdate, self).get_parser(prog_name)
parser.add_argument(
'-f', '--file', action='store', required=True,
help='Input yaml file with list of repositories')
parser.add_argument(
'id', type=int, help='Id of the {0}.'.format(self.entity_name))
return parser
def take_action(self, parsed_args):
data = self.client.get_attributes_metadata_by_id(parsed_args.id)
new_repos = utils.parse_yaml_file(parsed_args.file)
data["editable"]["repo_setup"]["repos"]["value"] = new_repos
self.client.update_attributes_metadata_by_id(parsed_args.id, data)
self.app.stdout.write(
"Repositories for the release with "
"id {rel_id} were set from {file}.\n".format(
rel_id=parsed_args.id,
file=parsed_args.file
)
)

View File

@@ -20,6 +20,7 @@ class Release(BaseObject):
class_api_path = "releases/"
instance_api_path = "releases/{0}/"
networks_path = 'releases/{0}/networks'
attributes_metadata_path = 'releases/{0}/attributes_metadata'
deployment_tasks_path = 'releases/{0}/deployment_tasks'
def get_networks(self):
@@ -30,6 +31,14 @@ class Release(BaseObject):
url = self.networks_path.format(self.id)
return self.connection.put_request(url, data)
def update_attributes_metadata(self, data):
url = self.attributes_metadata_path.format(self.id)
self.connection.put_request(url, data)
def get_attributes_metadata(self):
url = self.attributes_metadata_path.format(self.id)
return self.connection.get_request(url)
def get_deployment_tasks(self):
url = self.deployment_tasks_path.format(self.id)
return self.connection.get_request(url)

View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
#
# Copyright 2016 Mirantis, Inc.
#
# 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.
import mock
from fuelclient.tests.unit.v2.cli import test_engine
from fuelclient.tests.utils import fake_release
class TestReleaseCommand(test_engine.BaseCLITest):
"""Tests for fuel2 release * commands."""
def setUp(self):
super(TestReleaseCommand, self).setUp()
self.m_client.get_by_id.return_value = fake_release.get_fake_release()
self.m_client.get_attributes_metadata_by_id.return_value = \
fake_release.get_fake_attributes_metadata()
def test_release_list(self):
args = 'release list'
self.exec_command(args)
self.m_client.get_all.assert_called_once_with()
self.m_get_client.assert_called_once_with('release', mock.ANY)
def test_release_repos_list(self):
args = 'release repos list 1'
self.exec_command(args)
self.m_client.get_attributes_metadata_by_id.assert_called_once_with(1)
self.m_get_client.assert_called_once_with('release', mock.ANY)
@mock.patch('fuelclient.commands.release.utils.parse_yaml_file')
def test_release_repos_update(self, mock_parse_yaml):
args = 'release repos update 1 -f repos.yaml'
new_repos = [
{
"name": "fake",
"type": "deb",
"uri": "some_uri",
"priority": 1050,
"section": "main",
"suite": "trusty"
}
]
mock_parse_yaml.return_value = new_repos
data = fake_release.get_fake_attributes_metadata()
data["editable"]["repo_setup"]["repos"]["value"] = new_repos
self.exec_command(args)
mock_parse_yaml.assert_called_once_with('repos.yaml')
self.m_client.get_attributes_metadata_by_id.assert_called_once_with(1)
self.m_client.update_attributes_metadata_by_id \
.assert_called_once_with(1, data)
self.m_get_client.assert_called_once_with('release', mock.ANY)

View File

@@ -38,6 +38,7 @@ from fuelclient.tests.utils.fake_openstack_config \
import get_fake_openstack_config
from fuelclient.tests.utils.fake_plugin import get_fake_plugin
from fuelclient.tests.utils.fake_plugin import get_fake_plugins
from fuelclient.tests.utils.fake_release import get_fake_release
__all__ = (get_fake_deployment_history,
@@ -46,6 +47,7 @@ __all__ = (get_fake_deployment_history,
get_fake_yaml_deployment_info,
get_fake_yaml_network_conf,
get_fake_env,
get_fake_release,
get_fake_fuel_version,
get_fake_interface_config,
get_fake_network_group,

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
#
# Copyright 2016 Mirantis, Inc.
#
# 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.
def get_fake_attributes_metadata(repos=None):
return {
'editable': {
'repo_setup': {
'repos': {
'value': repos or [
{
'name': 'upstream',
'type': 'deb',
'uri': 'fake_upstream_uri',
'suite': 'trusty',
'section': 'main restricted',
'priority': 1000
},
{
'name': 'mos',
'type': 'deb',
'uri': 'fake_mos_uri',
'suite': 'mos',
'section': 'main restricted',
'priority': 1050
}
]
}
}
}
}
def get_fake_release(release_id=None, name=None, state=None,
operating_system=None, version=None, repos=None):
"""Create a random fake release
Returns the serialized and parametrized representation of a dumped Fuel
release. Represents the average amount of data.
"""
return {
'id': release_id or 1,
'name': name or 'Mitaka on Ubuntu 14.04',
'state': state or 'available',
'operating_system': operating_system or 'environment',
'version': version or 'mitaka-9.0',
'attributes_metadata': get_fake_attributes_metadata(repos=repos),
}

View File

@@ -22,6 +22,7 @@ from fuelclient.v1 import network_configuration
from fuelclient.v1 import network_group
from fuelclient.v1 import node
from fuelclient.v1 import openstack_config
from fuelclient.v1 import release
from fuelclient.v1 import plugins
from fuelclient.v1 import task
from fuelclient.v1 import vip
@@ -38,5 +39,6 @@ __all__ = ('cluster_settings',
'node',
'openstack_config',
'plugins',
'release',
'task',
'vip')

33
fuelclient/v1/release.py Normal file
View File

@@ -0,0 +1,33 @@
# Copyright 2016 Mirantis, Inc.
#
# 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.
from fuelclient import objects
from fuelclient.v1 import base_v1
class ReleaseClient(base_v1.BaseV1Client):
_entity_wrapper = objects.Release
def update_attributes_metadata_by_id(self, release_id, data):
release_obj = self._entity_wrapper(obj_id=release_id)
release_obj.update_attributes_metadata(data)
def get_attributes_metadata_by_id(self, release_id):
release_obj = self._entity_wrapper(obj_id=release_id)
return release_obj.get_attributes_metadata()
def get_client(connection):
return ReleaseClient(connection)

View File

@@ -65,6 +65,9 @@ fuelclient =
node_ansible-inventory=fuelclient.commands.node:NodeAnsibleInventory
plugins_list=fuelclient.commands.plugins:PluginsList
plugins_sync=fuelclient.commands.plugins:PluginsSync
release_list=fuelclient.commands.release:ReleaseList
release_repos_list=fuelclient.commands.release:ReleaseReposList
release_repos_update=fuelclient.commands.release:ReleaseReposUpdate
task_list=fuelclient.commands.task:TaskList
task_show=fuelclient.commands.task:TaskShow
task_history_show=fuelclient.commands.task:TaskHistoryShow