From a95976e77b0178217827a5a8bee724b08f7974b6 Mon Sep 17 00:00:00 2001 From: Kyrylo Maksymenko Date: Tue, 12 Feb 2019 15:32:12 +0200 Subject: [PATCH] add commands for import/export package --- cloudshell/rest/api.py | 42 ++++++++++++++++++++ tests/test_packaging_rest_api_client.py | 52 +++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/cloudshell/rest/api.py b/cloudshell/rest/api.py index a73fb9b..9dd31e8 100644 --- a/cloudshell/rest/api.py +++ b/cloudshell/rest/api.py @@ -117,6 +117,48 @@ def delete_shell(self, shell_name): if response.status_code != 200: raise Exception(response.text) + def export_package(self, topologies): + """Export a package with the topologies from the CloudShell + + :type topologies: list[str] + :rtype: str + :return: package content + """ + url = 'http://{0.ip}:{0.port}/API/Package/ExportPackage'.format(self) + response = post( + url, + headers={'Authorization': 'Basic ' + self.token}, + data={'TopologyNames': topologies}, + ) + + if response.status_code in (404, 405): + raise FeatureUnavailable() + + if not response.ok: + raise Exception(response.text) + + return response.content + + def import_package(self, package_path): + """Import the package to the CloudShell + + :type package_path: str + """ + url = 'http://{0.ip}:{0.port}/API/Package/ImportPackage'.format(self) + + with open(package_path, 'rb') as fo: + response = post( + url, + headers={'Authorization': 'Basic ' + self.token}, + files={'file': fo}, + ) + + if response.status_code in (404, 405): + raise FeatureUnavailable() + + if not response.ok: + raise Exception(response.text) + @staticmethod def _urlencode(s): return s.replace('+', '%2B').replace('/', '%2F').replace('=', '%3D') diff --git a/tests/test_packaging_rest_api_client.py b/tests/test_packaging_rest_api_client.py index 9d1393e..95ecf30 100644 --- a/tests/test_packaging_rest_api_client.py +++ b/tests/test_packaging_rest_api_client.py @@ -288,3 +288,55 @@ def test_delete_shell_shell_not_found_raises_error(self, mock_delete, mock_build # Act Assert client = PackagingRestApiClient('SERVER', 9000, 'USER', 'PASS', 'Global') self.assertRaises(ShellNotFoundException, client.delete_shell, 'shell') + + @patch('cloudshell.rest.api.urllib2.build_opener') + @patch('cloudshell.rest.api.post') + def test_export_package(self, mock_post, mock_build_opener): + # prepare + mock_build_opener.return_value.open.return_value.read.return_value = 'TOKEN' + + prepared_response = Response() + prepared_response.status_code = 201 + prepared_response._content = 'zip package content' + mock_post.return_value = prepared_response + + # act + client = PackagingRestApiClient('SERVER', 9000, 'USER', 'PASS', 'Global') + response = client.export_package(['topology_name']) + + # verify + mock_post.assert_called_once_with( + 'http://SERVER:9000/API/Package/ExportPackage', + headers={'Authorization': 'Basic TOKEN'}, + data={'TopologyNames': ['topology_name']}, + ) + self.assertEqual(response, 'zip package content') + + @patch('cloudshell.rest.api.urllib2.build_opener') + @patch('cloudshell.rest.api.post') + def test_import_package(self, mock_post, mock_build_opener): + # prepare + mock_build_opener.return_value.open.return_value.read.return_value = 'TOKEN' + + prepared_response = Response() + prepared_response.status_code = 201 + mock_post.return_value = prepared_response + + package_zip = self.fs.create_file('work//package.zip', contents='ZIP CONTENT') + + # act + client = PackagingRestApiClient('SERVER', 9000, 'USER', 'PASS', 'Global') + client.import_package('work//package.zip') + + # verify + mock_post.assert_called_once() + self.assertEqual( + 'http://SERVER:9000/API/Package/ImportPackage', + mock_post.call_args[0][0], + ) + self.assertEqual( + {'Authorization': 'Basic TOKEN'}, + mock_post.call_args[1]['headers'], + ) + file_object = mock_post.call_args[1]['files']['file'].get_object() + self.assertEqual(package_zip, file_object)