Skip to content

Commit 030fd71

Browse files
committed
Deprecate volume create --project and --user options
Cinder's volume create API does not support overriding the project_id and user_id, and it silently igores those API inputs. Cinder always uses the project and user info in the keystone identity associated with the API request. If a user specifies the --project or --user option, the volume create is aborted and a CommandError exception is raised. This prevents a volume from being created, but without the desired project/user values. A user wishing to specify alternate values can still do so using identity overrides (e.g. --os-username, --os-project-id). Story: 2002583 Task: 22192 Change-Id: Ia9f910ea1b0e61797e8c8c463fa28e7390f15bf9
1 parent a051bda commit 030fd71

3 files changed

Lines changed: 41 additions & 98 deletions

File tree

openstackclient/tests/unit/volume/v2/test_volume.py

Lines changed: 10 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,6 @@ def test_volume_create_min_options(self):
126126
name=self.new_volume.name,
127127
description=None,
128128
volume_type=None,
129-
user_id=None,
130-
project_id=None,
131129
availability_zone=None,
132130
metadata=None,
133131
imageRef=None,
@@ -177,8 +175,6 @@ def test_volume_create_options(self):
177175
name=self.new_volume.name,
178176
description=self.new_volume.description,
179177
volume_type=self.new_volume.volume_type,
180-
user_id=None,
181-
project_id=None,
182178
availability_zone=self.new_volume.availability_zone,
183179
metadata=None,
184180
imageRef=None,
@@ -191,95 +187,39 @@ def test_volume_create_options(self):
191187
self.assertEqual(self.columns, columns)
192188
self.assertEqual(self.datalist, data)
193189

194-
def test_volume_create_user_project_id(self):
195-
# Return a project
196-
self.projects_mock.get.return_value = self.project
197-
# Return a user
198-
self.users_mock.get.return_value = self.user
199-
190+
def test_volume_create_user(self):
200191
arglist = [
201192
'--size', str(self.new_volume.size),
202-
'--project', self.project.id,
203193
'--user', self.user.id,
204194
self.new_volume.name,
205195
]
206196
verifylist = [
207197
('size', self.new_volume.size),
208-
('project', self.project.id),
209198
('user', self.user.id),
210199
('name', self.new_volume.name),
211200
]
212201
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
213202

214-
# In base command class ShowOne in cliff, abstract method take_action()
215-
# returns a two-part tuple with a tuple of column names and a tuple of
216-
# data to be shown.
217-
columns, data = self.cmd.take_action(parsed_args)
218-
219-
self.volumes_mock.create.assert_called_with(
220-
size=self.new_volume.size,
221-
snapshot_id=None,
222-
name=self.new_volume.name,
223-
description=None,
224-
volume_type=None,
225-
user_id=self.user.id,
226-
project_id=self.project.id,
227-
availability_zone=None,
228-
metadata=None,
229-
imageRef=None,
230-
source_volid=None,
231-
consistencygroup_id=None,
232-
multiattach=False,
233-
scheduler_hints=None,
234-
)
235-
236-
self.assertEqual(self.columns, columns)
237-
self.assertEqual(self.datalist, data)
238-
239-
def test_volume_create_user_project_name(self):
240-
# Return a project
241-
self.projects_mock.get.return_value = self.project
242-
# Return a user
243-
self.users_mock.get.return_value = self.user
203+
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
204+
parsed_args)
205+
self.volumes_mock.create.assert_not_called()
244206

207+
def test_volume_create_project(self):
245208
arglist = [
246209
'--size', str(self.new_volume.size),
247-
'--project', self.project.name,
248-
'--user', self.user.name,
210+
'--project', self.project.id,
249211
self.new_volume.name,
250212
]
251213
verifylist = [
252214
('size', self.new_volume.size),
253-
('project', self.project.name),
254-
('user', self.user.name),
215+
('project', self.project.id),
255216
('name', self.new_volume.name),
256217
]
257218
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
258219

259-
# In base command class ShowOne in cliff, abstract method take_action()
260-
# returns a two-part tuple with a tuple of column names and a tuple of
261-
# data to be shown.
262-
columns, data = self.cmd.take_action(parsed_args)
263-
264-
self.volumes_mock.create.assert_called_with(
265-
size=self.new_volume.size,
266-
snapshot_id=None,
267-
name=self.new_volume.name,
268-
description=None,
269-
volume_type=None,
270-
user_id=self.user.id,
271-
project_id=self.project.id,
272-
availability_zone=None,
273-
metadata=None,
274-
imageRef=None,
275-
source_volid=None,
276-
consistencygroup_id=None,
277-
multiattach=False,
278-
scheduler_hints=None,
279-
)
280-
281-
self.assertEqual(self.columns, columns)
282-
self.assertEqual(self.datalist, data)
220+
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
221+
parsed_args)
222+
self.volumes_mock.create.assert_not_called()
283223

284224
def test_volume_create_properties(self):
285225
arglist = [
@@ -306,8 +246,6 @@ def test_volume_create_properties(self):
306246
name=self.new_volume.name,
307247
description=None,
308248
volume_type=None,
309-
user_id=None,
310-
project_id=None,
311249
availability_zone=None,
312250
metadata={'Alpha': 'a', 'Beta': 'b'},
313251
imageRef=None,
@@ -347,8 +285,6 @@ def test_volume_create_image_id(self):
347285
name=self.new_volume.name,
348286
description=None,
349287
volume_type=None,
350-
user_id=None,
351-
project_id=None,
352288
availability_zone=None,
353289
metadata=None,
354290
imageRef=image.id,
@@ -388,8 +324,6 @@ def test_volume_create_image_name(self):
388324
name=self.new_volume.name,
389325
description=None,
390326
volume_type=None,
391-
user_id=None,
392-
project_id=None,
393327
availability_zone=None,
394328
metadata=None,
395329
imageRef=image.id,
@@ -428,8 +362,6 @@ def test_volume_create_with_snapshot(self):
428362
name=self.new_volume.name,
429363
description=None,
430364
volume_type=None,
431-
user_id=None,
432-
project_id=None,
433365
availability_zone=None,
434366
metadata=None,
435367
imageRef=None,
@@ -469,8 +401,6 @@ def test_volume_create_with_bootable_and_readonly(self):
469401
name=self.new_volume.name,
470402
description=None,
471403
volume_type=None,
472-
user_id=None,
473-
project_id=None,
474404
availability_zone=None,
475405
metadata=None,
476406
imageRef=None,
@@ -514,8 +444,6 @@ def test_volume_create_with_nonbootable_and_readwrite(self):
514444
name=self.new_volume.name,
515445
description=None,
516446
volume_type=None,
517-
user_id=None,
518-
project_id=None,
519447
availability_zone=None,
520448
metadata=None,
521449
imageRef=None,
@@ -568,8 +496,6 @@ def test_volume_create_with_bootable_and_readonly_fail(
568496
name=self.new_volume.name,
569497
description=None,
570498
volume_type=None,
571-
user_id=None,
572-
project_id=None,
573499
availability_zone=None,
574500
metadata=None,
575501
imageRef=None,

openstackclient/volume/v2/volume.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,12 @@ def get_parser(self, prog_name):
9696
parser.add_argument(
9797
'--user',
9898
metavar='<user>',
99-
help=_('Specify an alternate user (name or ID)'),
99+
help=argparse.SUPPRESS,
100100
)
101101
parser.add_argument(
102102
'--project',
103103
metavar='<project>',
104-
help=_('Specify an alternate project (name or ID)'),
104+
help=argparse.SUPPRESS,
105105
)
106106
parser.add_argument(
107107
"--availability-zone",
@@ -159,7 +159,6 @@ def get_parser(self, prog_name):
159159

160160
def take_action(self, parsed_args):
161161
_check_size_arg(parsed_args)
162-
identity_client = self.app.client_manager.identity
163162
volume_client = self.app.client_manager.volume
164163
image_client = self.app.client_manager.image
165164

@@ -197,26 +196,29 @@ def take_action(self, parsed_args):
197196
# snapshot size.
198197
size = max(size or 0, snapshot_obj.size)
199198

200-
project = None
199+
# NOTE(abishop): Cinder's volumes.create() has 'project_id' and
200+
# 'user_id' args, but they're not wired up to anything. The only way
201+
# to specify an alternate project or user for the volume is to use
202+
# the identity overrides (e.g. "--os-project-id").
203+
#
204+
# Now, if the project or user arg is specified then the command is
205+
# rejected. Otherwise, Cinder would actually create a volume, but
206+
# without the specified property.
201207
if parsed_args.project:
202-
project = utils.find_resource(
203-
identity_client.projects,
204-
parsed_args.project).id
205-
206-
user = None
208+
raise exceptions.CommandError(
209+
_("ERROR: --project is deprecated, please use"
210+
" --os-project-name or --os-project-id instead."))
207211
if parsed_args.user:
208-
user = utils.find_resource(
209-
identity_client.users,
210-
parsed_args.user).id
212+
raise exceptions.CommandError(
213+
_("ERROR: --user is deprecated, please use"
214+
" --os-username instead."))
211215

212216
volume = volume_client.volumes.create(
213217
size=size,
214218
snapshot_id=snapshot,
215219
name=parsed_args.name,
216220
description=parsed_args.description,
217221
volume_type=parsed_args.type,
218-
user_id=user,
219-
project_id=project,
220222
availability_zone=parsed_args.availability_zone,
221223
metadata=parsed_args.property,
222224
imageRef=image,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
deprecations:
3+
- |
4+
The ``--project`` and ``--user`` options for the ``volume create``
5+
command have been deprecated. They are deprecated because Cinder's
6+
volume create API ignores the corresponding API inputs.
7+
fixes:
8+
- |
9+
Fix ``volume create`` by removing two broken options. The ``--project``
10+
and ``--user`` options were intended to specify an alternate project
11+
and/or user for the volume, but the Volume service's API does not
12+
support this behavior. This caused the volume to be created, but
13+
without the expected project/user values. However, an alternate
14+
project and/or user may be specified using identity overrides (e.g.
15+
--os-username, --os-project-id).

0 commit comments

Comments
 (0)