diff --git a/glareclient/osc/v1/blobs.py b/glareclient/osc/v1/blobs.py index 73d42f5..6848a64 100644 --- a/glareclient/osc/v1/blobs.py +++ b/glareclient/osc/v1/blobs.py @@ -155,3 +155,82 @@ class DownloadBlob(command.Command): 'blob. Please specify a local file with --file to save ' 'downloaded blob or redirect output to another source.') utils.exit(msg) + + +class AddLocation(command.ShowOne): + """Add external location""" + + def get_parser(self, prog_name): + parser = super(AddLocation, self).get_parser(prog_name) + parser.add_argument( + 'type_name', + metavar='', + action=TypeMapperAction, + help='Name of artifact type.', + ), + parser.add_argument( + 'id', + metavar='', + help='ID of the artifact to update.', + ) + parser.add_argument( + '--url', + metavar='', + help='External location that contains data to be uploaded.', + ) + parser.add_argument( + '--md5', + metavar='', + help='Specify a checksum md5.', + ) + parser.add_argument( + '--sha1', + metavar='', + help='Specify a checksum sha1.', + ) + parser.add_argument( + '--sha256', + metavar='', + help='Specify a checksum sha256.', + ) + parser.add_argument( + '--blob-property', + metavar='', + help='Name of the blob field.' + ) + parser.add_argument( + '--content-type', + metavar='', + default='application/vnd+openstack.glare-custom-location+json', + help='Content-type of the blob.' + ) + return parser + + def take_action(self, parsed_args): + LOG.debug('take_action({0})'.format(parsed_args)) + client = self.app.client_manager.artifact + + if not parsed_args.blob_property: + parsed_args.blob_property = _default_blob_property( + parsed_args.type_name) + + data = { + 'url': parsed_args.url, + 'md5': parsed_args.md5, + 'sha1': parsed_args.sha1, + 'sha256': parsed_args.sha256 + } + + client.artifacts.add_external_location( + parsed_args.id, + parsed_args.blob_property, + data, + content_type=parsed_args.content_type, + type_name=parsed_args.type_name) + + data = client.artifacts.get(parsed_args.id, + type_name=parsed_args.type_name) + + data_to_display = {'blob_property': parsed_args.blob_property} + data_to_display.update(data[parsed_args.blob_property]) + return self.dict2columns(data_to_display) diff --git a/glareclient/tests/unit/osc/v1/fakes.py b/glareclient/tests/unit/osc/v1/fakes.py index efdf713..986be8d 100644 --- a/glareclient/tests/unit/osc/v1/fakes.py +++ b/glareclient/tests/unit/osc/v1/fakes.py @@ -97,6 +97,8 @@ class TestArtifacts(utils.TestCommand): self.app.client_manager.artifact.artifacts.publish = mock_g_servs self.app.client_manager.artifact.blobs.upload_blob = mock_g_servs self.app.client_manager.artifact.blobs.download_blob = mock_g_servs + self.app.client_manager.artifact.blobs.add_external_location = \ + mock_g_servs self.app.client_manager.artifact.artifacts.get_type_schema = \ mock_g_schema g_utils.get_data_file = mock.MagicMock() diff --git a/glareclient/tests/unit/osc/v1/test_blob.py b/glareclient/tests/unit/osc/v1/test_blob.py index c66f7f6..396148f 100644 --- a/glareclient/tests/unit/osc/v1/test_blob.py +++ b/glareclient/tests/unit/osc/v1/test_blob.py @@ -236,3 +236,29 @@ class TestDownloadBlob(TestBlobs): parsed_args = self.check_parser(self.cmd, arglist, verify) self.cmd.take_action(parsed_args) + + +class TestAddLocation(TestBlobs): + def setUp(self): + super(TestAddLocation, self).setUp() + self.blob_mock.call.return_value = \ + api_art.Controller(self.http, type_name='images') + + # Command to test + self.cmd = osc_blob.AddLocation(self.app, None) + self.COLUMNS = ('blob_property', 'content_type', 'external', + 'md5', 'sha1', 'sha256', 'size', 'status', 'url') + + def test_add_location(self): + arglist = ['images', + 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba', + '--url', 'fake_url', + '--md5', "35d83e8eedfbdb87ff97d1f2761f8ebf", + '--sha1', "942854360eeec1335537702399c5aed940401602", + '--sha256', "d8a7834fc6652f316322d80196f6dcf2" + "94417030e37c15412e4deb7a67a367dd"] + verify = [('type_name', 'images'), ('url', 'fake_url')] + + parsed_args = self.check_parser(self.cmd, arglist, verify) + columns, data = self.cmd.take_action(parsed_args) + self.assertEqual(self.COLUMNS, columns) diff --git a/glareclient/tests/unit/v1/fixtures.py b/glareclient/tests/unit/v1/fixtures.py index 9f0e873..6a6c854 100644 --- a/glareclient/tests/unit/v1/fixtures.py +++ b/glareclient/tests/unit/v1/fixtures.py @@ -190,6 +190,12 @@ data_fixtures = { {} ) }, + '/artifacts/images/3a4560a1-e585-443e-9b39-553b46ec92a8/image': { + 'PUT': ( + {}, + '' + ), + }, '/schemas': { 'GET': ( {}, @@ -209,5 +215,4 @@ data_fixtures = { }}} ) } - } diff --git a/glareclient/tests/unit/v1/test_artifacts.py b/glareclient/tests/unit/v1/test_artifacts.py index 1c8c95e..7c68613 100644 --- a/glareclient/tests/unit/v1/test_artifacts.py +++ b/glareclient/tests/unit/v1/test_artifacts.py @@ -382,3 +382,18 @@ class TestController(testtools.TestCase): expect_call = [('GET', '/schemas/images', {}, None)] self.assertEqual(expect_call, self.api.calls) self.assertEqual(expect_data, data) + + def test_add_external_location(self): + art_id = '3a4560a1-e585-443e-9b39-553b46ec92a8' + data = self.controller.add_external_location(art_id, + 'image', + 'http://fake_url', + type_name='images') + expect_call = [ + ('PUT', + '/artifacts/images/3a4560a1-e585-443e-9b39-553b46ec92a8/image', + {'Content-Type': 'application/vnd+openstack.' + 'glare-custom-location+json'}, + 'http://fake_url')] + self.assertEqual(expect_call, self.api.calls) + self.assertIsNone(data) diff --git a/glareclient/v1/artifacts.py b/glareclient/v1/artifacts.py index 2eaca54..a8b87b3 100644 --- a/glareclient/v1/artifacts.py +++ b/glareclient/v1/artifacts.py @@ -215,6 +215,21 @@ class Controller(object): url = '/artifacts/%s/%s/%s' % (type_name, artifact_id, blob_property) self.http_client.put(url, headers=hdrs, data=data, stream=True) + def add_external_location(self, artifact_id, blob_property, data, + type_name=None, content_type=None): + """Add external location. + + :param artifact_id: ID of the artifact to download a blob + :param blob_property: blob property name + """ + content_type = (content_type or + 'application/vnd+openstack.glare-custom-location+json') + + type_name = self._check_type_name(type_name) + hdrs = {'Content-Type': content_type} + url = '/artifacts/%s/%s/%s' % (type_name, artifact_id, blob_property) + self.http_client.put(url, headers=hdrs, data=data) + def download_blob(self, artifact_id, blob_property, type_name=None, do_checksum=True): """Get blob data. diff --git a/setup.cfg b/setup.cfg index 76d4f10..32806f8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,6 +45,7 @@ openstack.artifact.v1 = artifact_reactivate = glareclient.osc.v1.artifacts:ReactivateArtifact artifact_publish = glareclient.osc.v1.artifacts:PublishArtifact artifact_upload = glareclient.osc.v1.blobs:UploadBlob + artifact_location = glareclient.osc.v1.blobs:AddLocation artifact_download = glareclient.osc.v1.blobs:DownloadBlob artifact_type-list = glareclient.osc.v1.artifacts:TypeList artifact_schema = glareclient.osc.v1.artifacts:TypeSchema