Add create operation for VIP related commands

Change-Id: I888f0da69cccc7cca1befa164ecd8fd75a3158f8
Closes-Bug: #1576255
This commit is contained in:
Artem Roma
2016-05-04 17:31:05 +03:00
parent cb84c58d73
commit a32c44471c
9 changed files with 190 additions and 14 deletions

View File

@@ -32,19 +32,43 @@ class VIPAction(Action):
self.file_serializer = serializers.FileFormatBasedSerializer()
self.args = (
Args.get_env_arg(required=True),
Args.get_create_arg("Create VIP"),
Args.get_upload_file_arg("Upload changed VIP configuration "
"from given file"),
Args.get_download_arg("Download VIP configuration"),
Args.get_file_arg("Target file with vip data."),
Args.get_ip_id_arg("IP address entity identifier"),
Args.get_ip_address_arg("IP address string"),
Args.get_network_id_arg("Network identifier"),
Args.get_network_role_arg("Network role string"),
Args.get_vip_name_arg("VIP name string"),
Args.get_vip_namespace_arg("VIP namespace string"),
)
self.flag_func_map = (
("create", self.create),
("upload", self.upload),
("download", self.download)
)
def create(self, params):
"""To create VIP for environment:
fuel --env 1 vip create --address 172.16.0.10 --network 1 \\
--name public_vip --namespace haproxy
"""
env = Environment(params.env)
vip_kwargs = {
"ip_addr": getattr(params, 'ip-address'),
"network": getattr(params, 'network'),
"vip_name": getattr(params, 'vip-name'),
}
vip_namespace = getattr(params, 'vip-namespace', None)
if vip_namespace is not None:
vip_kwargs['vip_namespace'] = vip_namespace
env.create_vip(**vip_kwargs)
print("VIP has been created")
def upload(self, params):
"""To upload VIP configuration from some
file for some environment:

View File

@@ -646,6 +646,31 @@ def get_vip_arg(help_msg):
)
def get_vip_name_arg(help_msg):
return get_str_arg(
"vip-name",
flags=("--name",),
help=help_msg
)
def get_vip_namespace_arg(help_msg, required=False):
return get_str_arg(
"vip-namespace",
flags=("--namespace",),
required=required,
help=help_msg
)
def get_ip_address_arg(help_msg):
return get_str_arg(
"ip-address",
flags=("--address", "--ip-addr"),
help=help_msg
)
def get_ip_id_arg(help_msg):
return get_int_arg(
"ip-address-id",

View File

@@ -30,6 +30,17 @@ class VipMixIn(object):
help='Environment identifier'
)
@staticmethod
def add_network_id_arg(parser):
parser.add_argument(
"-n",
"--network",
type=int,
default=None,
required=False,
help="Network identifier"
)
class VipDownload(VipMixIn, base.BaseCommand):
"""Download VIPs configuration."""
@@ -45,17 +56,6 @@ class VipDownload(VipMixIn, base.BaseCommand):
help="IP address entity identifier"
)
@staticmethod
def add_network_id_arg(parser):
parser.add_argument(
"-n",
"--network",
type=int,
default=None,
required=False,
help="Network identifier"
)
@staticmethod
def add_network_role_arg(parser):
parser.add_argument(
@@ -124,3 +124,59 @@ class VipUpload(VipMixIn, base.BaseCommand):
def take_action(self, args):
self.client.upload(env_id=args.env, file_path=args.file)
self.app.stdout.write("VIP configuration uploaded.")
class VipCreate(VipMixIn, base.BaseCommand):
"""Create VIP"""
@staticmethod
def add_vip_name_arg(parser):
parser.add_argument(
'-N',
'--name',
required=True,
type=str,
help="VIP name"
)
@staticmethod
def add_ip_addr_arg(parser):
parser.add_argument(
'-a',
'--address',
required=True,
type=str,
help="IP-address for the VIP"
)
@staticmethod
def add_vip_namespace_arg(parser):
parser.add_argument(
'--namespace',
required=False,
type=str,
help="VIP namespace"
)
def get_parser(self, prog_name):
parser = super(VipCreate, self).get_parser(prog_name)
self.add_env_id_arg(parser)
self.add_network_id_arg(parser)
self.add_vip_name_arg(parser)
self.add_ip_addr_arg(parser)
self.add_vip_namespace_arg(parser)
return parser
def take_action(self, args):
vip_kwargs = {
"env_id": args.env,
"ip_addr": args.address,
"network": args.network,
"vip_name": args.name,
}
if args.namespace is not None:
vip_kwargs['vip_namespace'] = args.namespace
self.client.create(**vip_kwargs)
self.app.stdout.write("VIP has been created.")

View File

@@ -640,3 +640,11 @@ class Environment(BaseObject):
:rtype: object
"""
return self.connection.put_request(self._get_ip_addrs_url(), data)
def create_vip(self, **vip_kwargs):
"""Create VIP through request to Nailgun API
:param vip_data: attributes of the VIP to be created
"""
return self.connection.post_request(self._get_ip_addrs_url(),
vip_kwargs)

View File

@@ -161,6 +161,10 @@ class TestVIPActions(base.UnitTestCase):
mopen.call_args_list[0][0][0]
)
def check_request(self, request_mock, url):
self.assertEqual(request_mock.call_count, 1)
self.assertIn(url, request_mock.last_request.url)
def test_vips_upload(self, mos, mopen):
url = '/api/v1/clusters/1/network_configuration/ips/vips/'
mopen().__enter__().read.return_value = MANY_VIPS_YAML
@@ -173,8 +177,7 @@ class TestVIPActions(base.UnitTestCase):
env_os.path.exists.return_value = True
self.execute(['fuel', 'vip', '--env', '1', '--upload', file_path])
self.assertEqual(env_os.path.exists.call_count, 1)
self.assertEqual(request_put.call_count, 1)
self.assertIn(url, request_put.last_request.url)
self.check_request(request_put, url)
# FileFormatBasedSerializer.read_from_file must not modify given
# file path string
self.assertEqual(file_path, mopen.call_args[0][0])
@@ -189,3 +192,24 @@ class TestVIPActions(base.UnitTestCase):
'fuel vip --env 1 --upload vips_1.yaml'.split()
)
self.assertIn("doesn't exist", mstderr.getvalue())
def test_create_vip(self, *_):
url = '/api/v1/clusters/1/network_configuration/ips/vips/'
request_post = self.m_request.post(url, json={})
env_id = 1
vip_data = {
"ip_addr": "127.0.0.1",
"network": -1,
"vip_name": 'test',
"vip_namespace": 'test-namespace'
}
self.execute(["fuel", "--env", str(env_id), "vip", "create",
"--ip-addr", vip_data['ip_addr'],
"--network", str(vip_data['network']),
"--name", vip_data['vip_name'],
"--namespace", vip_data['vip_namespace']])
self.check_request(request_post, url)
self.assertEqual(request_post.last_request.json(), vip_data)

View File

@@ -30,6 +30,22 @@ class TestVIPActions(test_engine.BaseCLITest):
self.m_client.__getattr__(method).assert_called_once_with(
**expected_kwargs)
def test_vip_create(self):
expected = {
"env_id": 1,
"ip_addr": '127.0.0.1',
"network": 1,
"vip_name": 'test',
"vip_namespace": 'test-namespace'
}
cmd_line = (
'--env {0} --network {1} --address {2} --name {3} --namespace {4}'
.format(expected['env_id'], expected['network'],
expected['ip_addr'], expected['vip_name'],
expected['vip_namespace'])
)
self._test_cmd('create', cmd_line, expected)
def test_vip_download(self):
self._test_cmd('download', '--env 1', dict(
env_id=1,

View File

@@ -64,3 +64,15 @@ class TestVipFacade(test_api.BaseLibTest):
written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0])
expected_yaml = yaml.safe_load(MANY_VIPS_YAML)
self.assertEqual(written_yaml, expected_yaml)
def test_vip_create(self):
expected = {'ip_addr': '127.0.0.1', 'vip_name': 'test', 'network': 1}
request_post = self.m_request.post(self.res_uri, json={})
self.client.create(
self.env_id,
ip_addr=expected['ip_addr'],
vip_name=expected['vip_name'],
network=expected['network']
)
self.assertTrue(request_post.called)
self.assertEqual(request_post.last_request.json(), expected)

View File

@@ -49,6 +49,16 @@ class VipClient(base_v1.BaseV1Client):
)
env.set_vips_data(vips_data)
@staticmethod
def create(env_id, ip_addr, network, vip_name):
env = objects.Environment(env_id)
vip_data = {
'ip_addr': ip_addr,
'network': network,
'vip_name': vip_name
}
env.create_vip(**vip_data)
def get_client(connection):
return VipClient(connection)

View File

@@ -74,8 +74,9 @@ fuelclient =
openstack-config_upload=fuelclient.commands.openstack_config:OpenstackConfigUpload
openstack-config_download=fuelclient.commands.openstack_config:OpenstackConfigDownload
openstack-config_execute=fuelclient.commands.openstack_config:OpenstackConfigExecute
vip_upload=fuelclient.commands.vip:VipUpload
vip_create=fuelclient.commands.vip:VipCreate
vip_download=fuelclient.commands.vip:VipDownload
vip_upload=fuelclient.commands.vip:VipUpload
[global]
setup-hooks =