OSC 2/4 Add Cluster Create and List
Add cluster create and cluster list for magnum's OSC plugin. Add cluster create and list unit tests Implements: blueprint openstackclient-support Co-Authored-By: Spyros Trigazis <strigazi@gmail.com> Change-Id: I815633e45df681e6bf089ae82d7451c2c0df05ef
This commit is contained in:
parent
7768eb6ea2
commit
98c4ed730d
|
@ -0,0 +1,127 @@
|
|||
# Copyright 2016 EasyStack. 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.
|
||||
|
||||
|
||||
from magnumclient.i18n import _
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
|
||||
|
||||
class CreateCluster(command.Command):
|
||||
_description = _("Create a cluster")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateCluster, self).get_parser(prog_name)
|
||||
# NOTE: All arguments are positional and, if not provided
|
||||
# with a default, required.
|
||||
parser.add_argument('--cluster-template',
|
||||
dest='cluster_template',
|
||||
required=True,
|
||||
metavar='<cluster-template>',
|
||||
help='ID or name of the cluster template.')
|
||||
parser.add_argument('--discovery-url',
|
||||
dest='discovery_url',
|
||||
metavar='<discovery-url>',
|
||||
help=('Specifies custom delivery url for '
|
||||
'node discovery.'))
|
||||
parser.add_argument('--docker-volume-size',
|
||||
dest='docker_volume_size',
|
||||
type=int,
|
||||
metavar='<docker-volume-size>',
|
||||
help=('The size in GB for the docker volume to '
|
||||
'use.'))
|
||||
parser.add_argument('--keypair',
|
||||
default=None,
|
||||
metavar='<keypair>',
|
||||
help='UUID or name of the keypair to use.')
|
||||
parser.add_argument('--master-count',
|
||||
dest='master_count',
|
||||
type=int,
|
||||
default=1,
|
||||
metavar='<master-count>',
|
||||
help='The number of master nodes for the cluster.')
|
||||
parser.add_argument('--name',
|
||||
metavar='<name>',
|
||||
help='Name of the cluster to create.')
|
||||
parser.add_argument('--node-count',
|
||||
dest='node_count',
|
||||
type=int,
|
||||
default=1,
|
||||
metavar='<node-count>',
|
||||
help='The cluster node count.')
|
||||
parser.add_argument('--timeout',
|
||||
type=int,
|
||||
default=60,
|
||||
metavar='<timeout>',
|
||||
help=('The timeout for cluster creation time. The '
|
||||
'default is 60 minutes.'))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
mag_client = self.app.client_manager.container_infra
|
||||
args = {
|
||||
'cluster_template_id': parsed_args.cluster_template,
|
||||
'create_timeout': parsed_args.timeout,
|
||||
'discovery_url': parsed_args.discovery_url,
|
||||
'docker_volume_size': parsed_args.docker_volume_size,
|
||||
'keypair': parsed_args.keypair,
|
||||
'master_count': parsed_args.master_count,
|
||||
'name': parsed_args.name,
|
||||
'node_count': parsed_args.node_count,
|
||||
}
|
||||
cluster = mag_client.clusters.create(**args)
|
||||
print("Request to create cluster %s accepted"
|
||||
% cluster.uuid)
|
||||
|
||||
|
||||
class ListCluster(command.Lister):
|
||||
_description = _("List clusters")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListCluster, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help=_('Maximum number of clusters to return'))
|
||||
parser.add_argument(
|
||||
'--sort-key',
|
||||
metavar='<sort-key>',
|
||||
help=_('Column to sort results by'))
|
||||
parser.add_argument(
|
||||
'--sort-dir',
|
||||
metavar='<sort-dir>',
|
||||
choices=['desc', 'asc'],
|
||||
help=_('Direction to sort. "asc" or "desc".'))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
mag_client = self.app.client_manager.container_infra
|
||||
columns = [
|
||||
'uuid', 'name', 'keypair', 'node_count', 'master_count', 'status']
|
||||
clusters = mag_client.clusters.list(limit=parsed_args.limit,
|
||||
sort_key=parsed_args.sort_key,
|
||||
sort_dir=parsed_args.sort_dir)
|
||||
return (
|
||||
columns,
|
||||
(utils.get_item_properties(c, columns) for c in clusters)
|
||||
)
|
|
@ -46,6 +46,7 @@ class FakeBaseModelManager(object):
|
|||
class MagnumFakeContainerInfra(object):
|
||||
def __init__(self):
|
||||
self.cluster_templates = FakeBaseModelManager()
|
||||
self.clusters = FakeBaseModelManager()
|
||||
|
||||
|
||||
class MagnumFakeClientManager(osc_fakes.FakeClientManager):
|
||||
|
@ -161,3 +162,48 @@ class FakeClusterTemplate(object):
|
|||
cts.append(FakeClusterTemplate.create_one_cluster_template(attrs))
|
||||
|
||||
return cts
|
||||
|
||||
|
||||
class FakeCluster(object):
|
||||
"""Fake one or more Cluster."""
|
||||
|
||||
@staticmethod
|
||||
def create_one_cluster(attrs=None):
|
||||
"""Create a fake Cluster.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:return:
|
||||
A FakeResource object, with flavor_id, image_id, and so on
|
||||
"""
|
||||
|
||||
attrs = attrs or {}
|
||||
|
||||
# set default attributes.
|
||||
cluster_info = {
|
||||
'status': 'CREATE_IN_PROGRESS',
|
||||
'cluster_template_id': 'fake-ct',
|
||||
'node_addresses': [],
|
||||
'uuid': '3a369884-b6ba-484f-a206-919b4b718aff',
|
||||
'stack_id': 'c4554582-77bd-4734-8f1a-72c3c40e5fb4',
|
||||
'status_reason': None,
|
||||
'created_at': '2017-03-16T18:40:39+00:00',
|
||||
'updated_at': '2017-03-16T18:40:45+00:00',
|
||||
'coe_version': None,
|
||||
'keypair': 'fakekey',
|
||||
'api_address': None,
|
||||
'master_addresses': [],
|
||||
'create_timeout': 60,
|
||||
'node_count': 1,
|
||||
'discovery_url': 'https://fake.cluster',
|
||||
'master_count': 1,
|
||||
'container_version': None,
|
||||
'name': 'fake-cluster'
|
||||
}
|
||||
|
||||
# Overwrite default attributes.
|
||||
cluster_info.update(attrs)
|
||||
|
||||
cluster = osc_fakes.FakeResource(info=copy.deepcopy(cluster_info),
|
||||
loaded=True)
|
||||
return cluster
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
# Copyright 2016 Easystack. 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.
|
||||
#
|
||||
|
||||
import copy
|
||||
import mock
|
||||
|
||||
from magnumclient.osc.v1 import clusters as osc_clusters
|
||||
from magnumclient.tests.osc.unit.v1 import fakes as magnum_fakes
|
||||
|
||||
|
||||
class TestCluster(magnum_fakes.TestMagnumClientOSCV1):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCluster, self).setUp()
|
||||
|
||||
self.clusters_mock = self.app.client_manager.container_infra.clusters
|
||||
|
||||
|
||||
class TestClusterCreate(TestCluster):
|
||||
|
||||
def setUp(self):
|
||||
super(TestClusterCreate, self).setUp()
|
||||
|
||||
attr = dict()
|
||||
attr['name'] = 'fake-cluster-1'
|
||||
self._cluster = magnum_fakes.FakeCluster.create_one_cluster(attr)
|
||||
|
||||
self._default_args = {
|
||||
'cluster_template_id': 'fake-ct',
|
||||
'create_timeout': 60,
|
||||
'discovery_url': None,
|
||||
'docker_volume_size': None,
|
||||
'keypair': None,
|
||||
'master_count': 1,
|
||||
'name': None,
|
||||
'node_count': 1
|
||||
}
|
||||
|
||||
self.clusters_mock.create = mock.Mock()
|
||||
self.clusters_mock.create.return_value = self._cluster
|
||||
|
||||
self.clusters_mock.get = mock.Mock()
|
||||
self.clusters_mock.get.return_value = copy.deepcopy(self._cluster)
|
||||
|
||||
self.clusters_mock.update = mock.Mock()
|
||||
self.clusters_mock.update.return_value = self._cluster
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_clusters.CreateCluster(self.app, None)
|
||||
|
||||
self.data = (
|
||||
self._cluster.status,
|
||||
self._cluster.cluster_template_id,
|
||||
self._cluster.node_addresses,
|
||||
self._cluster.uuid,
|
||||
self._cluster.stack_id,
|
||||
self._cluster.status_reason,
|
||||
self._cluster.created_at,
|
||||
self._cluster.updated_at,
|
||||
self._cluster.coe_version,
|
||||
self._cluster.keypair,
|
||||
self._cluster.api_address,
|
||||
self._cluster.master_addresses,
|
||||
self._cluster.create_timeout,
|
||||
self._cluster.node_count,
|
||||
self._cluster.discovery_url,
|
||||
self._cluster.master_count,
|
||||
self._cluster.container_version,
|
||||
self._cluster.name
|
||||
)
|
||||
|
||||
def test_cluster_create_required_args_pass(self):
|
||||
"""Verifies required arguments."""
|
||||
|
||||
arglist = [
|
||||
'--cluster-template', self._cluster.cluster_template_id
|
||||
]
|
||||
verifylist = [
|
||||
('cluster_template', self._cluster.cluster_template_id)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
self.clusters_mock.create.assert_called_with(**self._default_args)
|
||||
|
||||
def test_cluster_create_missing_required_arg(self):
|
||||
"""Verifies missing required arguments."""
|
||||
|
||||
arglist = [
|
||||
'--name', self._cluster.name
|
||||
]
|
||||
verifylist = [
|
||||
('name', self._cluster.name)
|
||||
]
|
||||
self.assertRaises(magnum_fakes.MagnumParseException,
|
||||
self.check_parser, self.cmd, arglist, verifylist)
|
||||
|
||||
|
||||
class TestClusterList(TestCluster):
|
||||
attr = dict()
|
||||
attr['name'] = 'fake-cluster-1'
|
||||
_cluster = magnum_fakes.FakeCluster.create_one_cluster(attr)
|
||||
|
||||
columns = [
|
||||
'uuid',
|
||||
'name',
|
||||
'keypair',
|
||||
'node_count',
|
||||
'master_count',
|
||||
'status'
|
||||
]
|
||||
|
||||
datalist = (
|
||||
(
|
||||
_cluster.uuid,
|
||||
_cluster.name,
|
||||
_cluster.keypair,
|
||||
_cluster.node_count,
|
||||
_cluster.master_count,
|
||||
_cluster.status
|
||||
),
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super(TestClusterList, self).setUp()
|
||||
|
||||
self.clusters_mock.list = mock.Mock()
|
||||
self.clusters_mock.list.return_value = [self._cluster]
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_clusters.ListCluster(self.app, None)
|
||||
|
||||
def test_cluster_list_no_options(self):
|
||||
arglist = []
|
||||
verifylist = [
|
||||
('limit', None),
|
||||
('sort_key', None),
|
||||
('sort_dir', None),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.clusters_mock.list.assert_called_with(
|
||||
limit=None,
|
||||
sort_dir=None,
|
||||
sort_key=None,
|
||||
)
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(self.datalist, tuple(data))
|
||||
|
||||
def test_cluster_list_options(self):
|
||||
arglist = [
|
||||
'--limit', '1',
|
||||
'--sort-key', 'key',
|
||||
'--sort-dir', 'asc'
|
||||
]
|
||||
verifylist = [
|
||||
('limit', 1),
|
||||
('sort_key', 'key'),
|
||||
('sort_dir', 'asc')
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
self.clusters_mock.list.assert_called_with(
|
||||
limit=1,
|
||||
sort_dir='asc',
|
||||
sort_key='key',
|
||||
)
|
||||
|
||||
def test_cluster_list_bad_sort_dir_fail(self):
|
||||
arglist = [
|
||||
'--sort-dir', 'foo'
|
||||
]
|
||||
verifylist = [
|
||||
('limit', None),
|
||||
('sort_key', None),
|
||||
('sort_dir', 'foo'),
|
||||
('fields', None),
|
||||
]
|
||||
|
||||
self.assertRaises(magnum_fakes.MagnumParseException,
|
||||
self.check_parser, self.cmd, arglist, verifylist)
|
|
@ -33,6 +33,9 @@ openstack.container_infra.v1 =
|
|||
coe_cluster_template_create = magnumclient.osc.v1.cluster_templates:CreateClusterTemplate
|
||||
coe_cluster_template_list = magnumclient.osc.v1.cluster_templates:ListTemplateCluster
|
||||
|
||||
coe_cluster_create = magnumclient.osc.v1.clusters:CreateCluster
|
||||
coe_cluster_list = magnumclient.osc.v1.clusters:ListCluster
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
|
|
Loading…
Reference in New Issue