From a32c44471c68e24a5019d0d446f145541b0301dc Mon Sep 17 00:00:00 2001 From: Artem Roma Date: Wed, 4 May 2016 17:31:05 +0300 Subject: [PATCH] Add create operation for VIP related commands Change-Id: I888f0da69cccc7cca1befa164ecd8fd75a3158f8 Closes-Bug: #1576255 --- fuelclient/cli/actions/vip.py | 24 +++++++ fuelclient/cli/arguments.py | 25 +++++++ fuelclient/commands/vip.py | 78 ++++++++++++++++++--- fuelclient/objects/environment.py | 8 +++ fuelclient/tests/unit/v1/test_vip_action.py | 28 +++++++- fuelclient/tests/unit/v2/cli/test_vip.py | 16 +++++ fuelclient/tests/unit/v2/lib/test_vip.py | 12 ++++ fuelclient/v1/vip.py | 10 +++ setup.cfg | 3 +- 9 files changed, 190 insertions(+), 14 deletions(-) diff --git a/fuelclient/cli/actions/vip.py b/fuelclient/cli/actions/vip.py index d0f56f12..bbd419a2 100644 --- a/fuelclient/cli/actions/vip.py +++ b/fuelclient/cli/actions/vip.py @@ -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: diff --git a/fuelclient/cli/arguments.py b/fuelclient/cli/arguments.py index 3d840490..337d9c9c 100644 --- a/fuelclient/cli/arguments.py +++ b/fuelclient/cli/arguments.py @@ -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", diff --git a/fuelclient/commands/vip.py b/fuelclient/commands/vip.py index 26078236..5f070f79 100644 --- a/fuelclient/commands/vip.py +++ b/fuelclient/commands/vip.py @@ -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.") diff --git a/fuelclient/objects/environment.py b/fuelclient/objects/environment.py index fc3745be..f4f147e1 100644 --- a/fuelclient/objects/environment.py +++ b/fuelclient/objects/environment.py @@ -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) diff --git a/fuelclient/tests/unit/v1/test_vip_action.py b/fuelclient/tests/unit/v1/test_vip_action.py index fda0a3ca..1bdc4160 100644 --- a/fuelclient/tests/unit/v1/test_vip_action.py +++ b/fuelclient/tests/unit/v1/test_vip_action.py @@ -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) diff --git a/fuelclient/tests/unit/v2/cli/test_vip.py b/fuelclient/tests/unit/v2/cli/test_vip.py index 22abf2a9..1118166b 100644 --- a/fuelclient/tests/unit/v2/cli/test_vip.py +++ b/fuelclient/tests/unit/v2/cli/test_vip.py @@ -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, diff --git a/fuelclient/tests/unit/v2/lib/test_vip.py b/fuelclient/tests/unit/v2/lib/test_vip.py index 0511d262..68267223 100644 --- a/fuelclient/tests/unit/v2/lib/test_vip.py +++ b/fuelclient/tests/unit/v2/lib/test_vip.py @@ -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) diff --git a/fuelclient/v1/vip.py b/fuelclient/v1/vip.py index c97efc9b..775a6a5c 100644 --- a/fuelclient/v1/vip.py +++ b/fuelclient/v1/vip.py @@ -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) diff --git a/setup.cfg b/setup.cfg index 53e2160e..8be65c71 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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 =