From abedb2836d3b68a64bdd6b06c4a2ecc847b88d93 Mon Sep 17 00:00:00 2001 From: Idan Narotzki Date: Mon, 7 Aug 2017 16:03:01 +0000 Subject: [PATCH] Allow to delete blobs with external urls This patch support new API request to delete blobs from artifact: DELETE /artifacts/{type_name}/{artifact_id}/{blob_name} if user wants to delete internal blob glare raises 403 error. Co-Authored-By: Mike Fedosin Change-Id: I8daa686df3a05158f59b33546397b23a494d5ab1 --- glareclient/osc/v1/blobs.py | 49 +++++++++++++++++++++ glareclient/shell.py | 3 +- glareclient/tests/unit/osc/v1/test_blob.py | 28 ++++++++++++ glareclient/tests/unit/v1/test_artifacts.py | 10 +++++ glareclient/v1/artifacts.py | 12 +++++ setup.cfg | 1 + 6 files changed, 102 insertions(+), 1 deletion(-) diff --git a/glareclient/osc/v1/blobs.py b/glareclient/osc/v1/blobs.py index 23e9fbb..846511f 100644 --- a/glareclient/osc/v1/blobs.py +++ b/glareclient/osc/v1/blobs.py @@ -275,3 +275,52 @@ class AddLocation(command.ShowOne): else: data_to_display.update(data[parsed_args.blob_property]) return self.dict2columns(data_to_display) + + +class RemoveLocation(command.ShowOne): + """Remove external location""" + + def get_parser(self, prog_name): + parser = super(RemoveLocation, self).get_parser(prog_name) + parser.add_argument( + 'type_name', + metavar='', + action=TypeMapperAction, + help='Name of artifact type.', + ), + parser.add_argument( + 'name', + metavar='', + help='Name or id of the artifact to download.', + ), + parser.add_argument( + '--artifact-version', '-V', + metavar='', + default='latest', + help='Version of the artifact.', + ), + parser.add_argument( + '--id', '-i', + action='store_true', + help='The specified id of the artifact.', + ), + parser.add_argument( + '--blob-property', '-p', + metavar='', + help='Name of the blob field.' + ) + return parser + + def take_action(self, parsed_args): + LOG.debug('take_action({0})'.format(parsed_args)) + client = self.app.client_manager.artifact + af_id = utils.get_artifact_id(client, parsed_args) + + if not parsed_args.blob_property: + parsed_args.blob_property = _default_blob_property( + parsed_args.type_name) + + client.artifacts.remove_external_location( + af_id, + parsed_args.blob_property, + type_name=parsed_args.type_name) diff --git a/glareclient/shell.py b/glareclient/shell.py index bddd8b6..9a279ef 100644 --- a/glareclient/shell.py +++ b/glareclient/shell.py @@ -293,7 +293,8 @@ class GlareShell(app.App): 'schema': glareclient.osc.v1.artifacts.TypeSchema, 'upload': glareclient.osc.v1.blobs.UploadBlob, 'download': glareclient.osc.v1.blobs.DownloadBlob, - 'location': glareclient.osc.v1.blobs.AddLocation + 'location': glareclient.osc.v1.blobs.AddLocation, + 'remove-location': glareclient.osc.v1.blobs.RemoveLocation } diff --git a/glareclient/tests/unit/osc/v1/test_blob.py b/glareclient/tests/unit/osc/v1/test_blob.py index 1c68f1f..91d732f 100644 --- a/glareclient/tests/unit/osc/v1/test_blob.py +++ b/glareclient/tests/unit/osc/v1/test_blob.py @@ -221,3 +221,31 @@ class TestAddLocation(TestBlobs): columns, data = self.cmd.take_action(parsed_args) self.app.client_manager.artifact.artifacts.get = fakes.mock_get self.assertEqual(self.COLUMNS, columns) + + +class TestRemoveLocation(TestBlobs): + def setUp(self): + super(TestRemoveLocation, self).setUp() + self.blob_mock.call.return_value = \ + api_art.Controller(self.http, type_name='images') + + # Command to test + self.cmd = osc_blob.RemoveLocation(self.app, None) + + def test_remove_location(self): + arglist = ['images', + 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba', '--id'] + verify = [('type_name', 'images'), + ('name', 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba'), + ('id', True)] + parsed_args = self.check_parser(self.cmd, arglist, verify) + self.assertIsNone(self.cmd.take_action(parsed_args)) + + def test_remove_dict_location(self): + arglist = ['images', '--blob-property', 'nested_templates/blob', + 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba', '--id'] + verify = [('type_name', 'images'), + ('name', 'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba'), + ('id', True)] + parsed_args = self.check_parser(self.cmd, arglist, verify) + self.assertIsNone(self.cmd.take_action(parsed_args)) diff --git a/glareclient/tests/unit/v1/test_artifacts.py b/glareclient/tests/unit/v1/test_artifacts.py index ef235c7..9052cdd 100644 --- a/glareclient/tests/unit/v1/test_artifacts.py +++ b/glareclient/tests/unit/v1/test_artifacts.py @@ -151,6 +151,16 @@ class TestController(testtools.TestCase): 'application/vnd+openstack.glare-custom-location+json'}) self.assertIsNone(resp) + def test_remove_external_location(self): + art_id = '3a4560a1-e585-443e-9b39-553b46ec92a8' + resp = self.c.remove_external_location( + art_id, 'image', + type_name='images') + self.c.http_client.delete.assert_called_once_with( + '/artifacts/checked_name/' + '3a4560a1-e585-443e-9b39-553b46ec92a8/image') + self.assertIsNone(resp) + def test_add_tag(self): art_id = '07a679d8-d0a8-45ff-8d6e-2f32f2097b7c' d = {'tags': ['a', 'b', 'c']} diff --git a/glareclient/v1/artifacts.py b/glareclient/v1/artifacts.py index 55d7776..28bf8e9 100644 --- a/glareclient/v1/artifacts.py +++ b/glareclient/v1/artifacts.py @@ -267,6 +267,18 @@ class Controller(object): raise exc.HTTPBadRequest("json is malformed.") self.http_client.put(url, headers=hdrs, data=data) + def remove_external_location(self, artifact_id, blob_property, + type_name=None): + """Remove external location. + + :param artifact_id: ID of the artifact with external location + to be removed + :param blob_property: blob property name + """ + type_name = self._check_type_name(type_name) + url = '/artifacts/%s/%s/%s' % (type_name, artifact_id, blob_property) + self.http_client.delete(url) + 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 3e85217..32791e1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -49,6 +49,7 @@ openstack.artifact.v1 = artifact_publish = glareclient.osc.v1.artifacts:PublishArtifact artifact_upload = glareclient.osc.v1.blobs:UploadBlob artifact_location = glareclient.osc.v1.blobs:AddLocation + artifact_remove-location = glareclient.osc.v1.blobs:RemoveLocation artifact_download = glareclient.osc.v1.blobs:DownloadBlob artifact_type-list = glareclient.osc.v1.artifacts:TypeList artifact_schema = glareclient.osc.v1.artifacts:TypeSchema