summaryrefslogtreecommitdiff
path: root/novaclient/tests/unit/v2/test_shell.py
diff options
context:
space:
mode:
Diffstat (limited to 'novaclient/tests/unit/v2/test_shell.py')
-rw-r--r--novaclient/tests/unit/v2/test_shell.py2455
1 files changed, 2455 insertions, 0 deletions
diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py
new file mode 100644
index 0000000..49e1581
--- /dev/null
+++ b/novaclient/tests/unit/v2/test_shell.py
@@ -0,0 +1,2455 @@
1# Copyright 2010 Jacob Kaplan-Moss
2
3# Copyright 2011 OpenStack Foundation
4# Copyright 2012 IBM Corp.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import base64
20import datetime
21import os
22
23import fixtures
24import mock
25from oslo.utils import timeutils
26import six
27from six.moves import builtins
28
29import novaclient.client
30from novaclient import exceptions
31import novaclient.shell
32from novaclient.tests.unit import utils
33from novaclient.tests.unit.v2 import fakes
34import novaclient.v2.shell
35
36
37class ShellFixture(fixtures.Fixture):
38 def setUp(self):
39 super(ShellFixture, self).setUp()
40 self.shell = novaclient.shell.OpenStackComputeShell()
41
42 def tearDown(self):
43 # For some method like test_image_meta_bad_action we are
44 # testing a SystemExit to be thrown and object self.shell has
45 # no time to get instantatiated which is OK in this case, so
46 # we make sure the method is there before launching it.
47 if hasattr(self.shell, 'cs'):
48 self.shell.cs.clear_callstack()
49 super(ShellFixture, self).tearDown()
50
51
52class ShellTest(utils.TestCase):
53 FAKE_ENV = {
54 'NOVA_USERNAME': 'username',
55 'NOVA_PASSWORD': 'password',
56 'NOVA_PROJECT_ID': 'project_id',
57 'OS_COMPUTE_API_VERSION': '2',
58 'NOVA_URL': 'http://no.where',
59 'OS_AUTH_URL': 'http://no.where/v2.0',
60 }
61
62 def setUp(self):
63 """Run before each test."""
64 super(ShellTest, self).setUp()
65
66 for var in self.FAKE_ENV:
67 self.useFixture(fixtures.EnvironmentVariable(var,
68 self.FAKE_ENV[var]))
69 self.shell = self.useFixture(ShellFixture()).shell
70
71 self.useFixture(fixtures.MonkeyPatch(
72 'novaclient.client.get_client_class',
73 lambda *_: fakes.FakeClient))
74
75 @mock.patch('sys.stdout', new_callable=six.StringIO)
76 def run_command(self, cmd, mock_stdout):
77 if isinstance(cmd, list):
78 self.shell.main(cmd)
79 else:
80 self.shell.main(cmd.split())
81 return mock_stdout.getvalue()
82
83 def assert_called(self, method, url, body=None, **kwargs):
84 return self.shell.cs.assert_called(method, url, body, **kwargs)
85
86 def assert_called_anytime(self, method, url, body=None):
87 return self.shell.cs.assert_called_anytime(method, url, body)
88
89 def test_agents_list_with_hypervisor(self):
90 self.run_command('agent-list --hypervisor xen')
91 self.assert_called('GET', '/os-agents?hypervisor=xen')
92
93 def test_agents_create(self):
94 self.run_command('agent-create win x86 7.0 '
95 '/xxx/xxx/xxx '
96 'add6bb58e139be103324d04d82d8f546 '
97 'kvm')
98 self.assert_called(
99 'POST', '/os-agents',
100 {'agent': {
101 'hypervisor': 'kvm',
102 'os': 'win',
103 'architecture': 'x86',
104 'version': '7.0',
105 'url': '/xxx/xxx/xxx',
106 'md5hash': 'add6bb58e139be103324d04d82d8f546'}})
107
108 def test_agents_delete(self):
109 self.run_command('agent-delete 1')
110 self.assert_called('DELETE', '/os-agents/1')
111
112 def test_agents_modify(self):
113 self.run_command('agent-modify 1 8.0 /yyy/yyyy/yyyy '
114 'add6bb58e139be103324d04d82d8f546')
115 self.assert_called('PUT', '/os-agents/1',
116 {"para": {
117 "url": "/yyy/yyyy/yyyy",
118 "version": "8.0",
119 "md5hash": "add6bb58e139be103324d04d82d8f546"}})
120
121 def test_boot(self):
122 self.run_command('boot --flavor 1 --image 1 some-server')
123 self.assert_called_anytime(
124 'POST', '/servers',
125 {'server': {
126 'flavorRef': '1',
127 'name': 'some-server',
128 'imageRef': '1',
129 'min_count': 1,
130 'max_count': 1,
131 }},
132 )
133
134 def test_boot_image_with(self):
135 self.run_command("boot --flavor 1"
136 " --image-with test_key=test_value some-server")
137 self.assert_called_anytime(
138 'POST', '/servers',
139 {'server': {
140 'flavorRef': '1',
141 'name': 'some-server',
142 'imageRef': '1',
143 'min_count': 1,
144 'max_count': 1,
145 }},
146 )
147
148 def test_boot_key(self):
149 self.run_command('boot --flavor 1 --image 1 --key_name 1 some-server')
150 self.assert_called_anytime(
151 'POST', '/servers',
152 {'server': {
153 'flavorRef': '1',
154 'name': 'some-server',
155 'imageRef': '1',
156 'key_name': '1',
157 'min_count': 1,
158 'max_count': 1,
159 }},
160 )
161
162 def test_boot_user_data(self):
163 testfile = os.path.join(os.path.dirname(__file__), 'testfile.txt')
164 data = open(testfile).read().encode('utf-8')
165 expected_file_data = base64.b64encode(data).decode('utf-8')
166 self.run_command(
167 'boot --flavor 1 --image 1 --user_data %s some-server' % testfile)
168 self.assert_called_anytime(
169 'POST', '/servers',
170 {'server': {
171 'flavorRef': '1',
172 'name': 'some-server',
173 'imageRef': '1',
174 'min_count': 1,
175 'max_count': 1,
176 'user_data': expected_file_data
177 }},
178 )
179
180 def test_boot_avzone(self):
181 self.run_command(
182 'boot --flavor 1 --image 1 --availability-zone avzone '
183 'some-server')
184 self.assert_called_anytime(
185 'POST', '/servers',
186 {'server': {
187 'flavorRef': '1',
188 'name': 'some-server',
189 'imageRef': '1',
190 'availability_zone': 'avzone',
191 'min_count': 1,
192 'max_count': 1
193 }},
194 )
195
196 def test_boot_secgroup(self):
197 self.run_command(
198 'boot --flavor 1 --image 1 --security-groups secgroup1,'
199 'secgroup2 some-server')
200 self.assert_called_anytime(
201 'POST', '/servers',
202 {'server': {
203 'security_groups': [{'name': 'secgroup1'},
204 {'name': 'secgroup2'}],
205 'flavorRef': '1',
206 'name': 'some-server',
207 'imageRef': '1',
208 'min_count': 1,
209 'max_count': 1,
210 }},
211 )
212
213 def test_boot_config_drive(self):
214 self.run_command(
215 'boot --flavor 1 --image 1 --config-drive 1 some-server')
216 self.assert_called_anytime(
217 'POST', '/servers',
218 {'server': {
219 'flavorRef': '1',
220 'name': 'some-server',
221 'imageRef': '1',
222 'min_count': 1,
223 'max_count': 1,
224 'config_drive': True
225 }},
226 )
227
228 def test_boot_config_drive_custom(self):
229 self.run_command(
230 'boot --flavor 1 --image 1 --config-drive /dev/hda some-server')
231 self.assert_called_anytime(
232 'POST', '/servers',
233 {'server': {
234 'flavorRef': '1',
235 'name': 'some-server',
236 'imageRef': '1',
237 'min_count': 1,
238 'max_count': 1,
239 'config_drive': '/dev/hda'
240 }},
241 )
242
243 def test_boot_invalid_user_data(self):
244 invalid_file = os.path.join(os.path.dirname(__file__),
245 'no_such_file')
246 cmd = ('boot some-server --flavor 1 --image 1'
247 ' --user_data %s' % invalid_file)
248 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
249
250 def test_boot_no_image_no_bdms(self):
251 cmd = 'boot --flavor 1 some-server'
252 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
253
254 def test_boot_no_flavor(self):
255 cmd = 'boot --image 1 some-server'
256 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
257
258 def test_boot_no_image_bdms(self):
259 self.run_command(
260 'boot --flavor 1 --block_device_mapping vda=blah:::0 some-server'
261 )
262 self.assert_called_anytime(
263 'POST', '/os-volumes_boot',
264 {'server': {
265 'flavorRef': '1',
266 'name': 'some-server',
267 'block_device_mapping': [
268 {
269 'volume_id': 'blah',
270 'delete_on_termination': '0',
271 'device_name': 'vda',
272 'uuid': 'blah',
273 'boot_index': 0,
274 'source_type': ''
275 }
276 ],
277 'imageRef': '',
278 'min_count': 1,
279 'max_count': 1,
280 }},
281 )
282
283 def test_boot_image_bdms_v2(self):
284 self.run_command(
285 'boot --flavor 1 --image 1 --block-device id=fake-id,'
286 'source=volume,dest=volume,device=vda,size=1,format=ext4,'
287 'type=disk,shutdown=preserve some-server'
288 )
289 self.assert_called_anytime(
290 'POST', '/os-volumes_boot',
291 {'server': {
292 'flavorRef': '1',
293 'name': 'some-server',
294 'block_device_mapping_v2': [
295 {
296 'uuid': 1,
297 'source_type': 'image',
298 'destination_type': 'local',
299 'boot_index': 0,
300 'delete_on_termination': True,
301 },
302 {
303 'uuid': 'fake-id',
304 'source_type': 'volume',
305 'destination_type': 'volume',
306 'device_name': 'vda',
307 'volume_size': '1',
308 'guest_format': 'ext4',
309 'device_type': 'disk',
310 'delete_on_termination': False,
311 },
312 ],
313 'imageRef': '1',
314 'min_count': 1,
315 'max_count': 1,
316 }},
317 )
318
319 def test_boot_no_image_bdms_v2(self):
320 self.run_command(
321 'boot --flavor 1 --block-device id=fake-id,source=volume,'
322 'dest=volume,bus=virtio,device=vda,size=1,format=ext4,bootindex=0,'
323 'type=disk,shutdown=preserve some-server'
324 )
325 self.assert_called_anytime(
326 'POST', '/os-volumes_boot',
327 {'server': {
328 'flavorRef': '1',
329 'name': 'some-server',
330 'block_device_mapping_v2': [
331 {
332 'uuid': 'fake-id',
333 'source_type': 'volume',
334 'destination_type': 'volume',
335 'disk_bus': 'virtio',
336 'device_name': 'vda',
337 'volume_size': '1',
338 'guest_format': 'ext4',
339 'boot_index': '0',
340 'device_type': 'disk',
341 'delete_on_termination': False,
342 }
343 ],
344 'imageRef': '',
345 'min_count': 1,
346 'max_count': 1,
347 }},
348 )
349
350 cmd = 'boot --flavor 1 --boot-volume fake-id some-server'
351 self.run_command(cmd)
352 self.assert_called_anytime(
353 'POST', '/os-volumes_boot',
354 {'server': {
355 'flavorRef': '1',
356 'name': 'some-server',
357 'block_device_mapping_v2': [
358 {
359 'uuid': 'fake-id',
360 'source_type': 'volume',
361 'destination_type': 'volume',
362 'boot_index': 0,
363 'delete_on_termination': False,
364 }
365 ],
366 'imageRef': '',
367 'min_count': 1,
368 'max_count': 1,
369 }},
370 )
371
372 cmd = 'boot --flavor 1 --snapshot fake-id some-server'
373 self.run_command(cmd)
374 self.assert_called_anytime(
375 'POST', '/os-volumes_boot',
376 {'server': {
377 'flavorRef': '1',
378 'name': 'some-server',
379 'block_device_mapping_v2': [
380 {
381 'uuid': 'fake-id',
382 'source_type': 'snapshot',
383 'destination_type': 'volume',
384 'boot_index': 0,
385 'delete_on_termination': False,
386 }
387 ],
388 'imageRef': '',
389 'min_count': 1,
390 'max_count': 1,
391 }},
392 )
393
394 self.run_command('boot --flavor 1 --swap 1 some-server')
395 self.assert_called_anytime(
396 'POST', '/os-volumes_boot',
397 {'server': {
398 'flavorRef': '1',
399 'name': 'some-server',
400 'block_device_mapping_v2': [
401 {
402 'source_type': 'blank',
403 'destination_type': 'local',
404 'boot_index': -1,
405 'guest_format': 'swap',
406 'volume_size': '1',
407 'delete_on_termination': True,
408 }
409 ],
410 'imageRef': '',
411 'min_count': 1,
412 'max_count': 1,
413 }},
414 )
415
416 self.run_command(
417 'boot --flavor 1 --ephemeral size=1,format=ext4 some-server'
418 )
419 self.assert_called_anytime(
420 'POST', '/os-volumes_boot',
421 {'server': {
422 'flavorRef': '1',
423 'name': 'some-server',
424 'block_device_mapping_v2': [
425 {
426 'source_type': 'blank',
427 'destination_type': 'local',
428 'boot_index': -1,
429 'guest_format': 'ext4',
430 'volume_size': '1',
431 'delete_on_termination': True,
432 }
433 ],
434 'imageRef': '',
435 'min_count': 1,
436 'max_count': 1,
437 }},
438 )
439
440 def test_boot_metadata(self):
441 self.run_command('boot --image 1 --flavor 1 --meta foo=bar=pants'
442 ' --meta spam=eggs some-server ')
443 self.assert_called_anytime(
444 'POST', '/servers',
445 {'server': {
446 'flavorRef': '1',
447 'name': 'some-server',
448 'imageRef': '1',
449 'metadata': {'foo': 'bar=pants', 'spam': 'eggs'},
450 'min_count': 1,
451 'max_count': 1,
452 }},
453 )
454
455 def test_boot_hints(self):
456 self.run_command('boot --image 1 --flavor 1 '
457 '--hint a=b0=c0 --hint a=b1=c1 some-server ')
458 self.assert_called_anytime(
459 'POST', '/servers',
460 {
461 'server': {
462 'flavorRef': '1',
463 'name': 'some-server',
464 'imageRef': '1',
465 'min_count': 1,
466 'max_count': 1,
467 },
468 'os:scheduler_hints': {'a': ['b0=c0', 'b1=c1']},
469 },
470 )
471
472 def test_boot_nics(self):
473 cmd = ('boot --image 1 --flavor 1 '
474 '--nic net-id=a=c,v4-fixed-ip=10.0.0.1 some-server')
475 self.run_command(cmd)
476 self.assert_called_anytime(
477 'POST', '/servers',
478 {
479 'server': {
480 'flavorRef': '1',
481 'name': 'some-server',
482 'imageRef': '1',
483 'min_count': 1,
484 'max_count': 1,
485 'networks': [
486 {'uuid': 'a=c', 'fixed_ip': '10.0.0.1'},
487 ],
488 },
489 },
490 )
491
492 def test_boot_nics_ipv6(self):
493 cmd = ('boot --image 1 --flavor 1 '
494 '--nic net-id=a=c,v6-fixed-ip=2001:db9:0:1::10 some-server')
495 self.run_command(cmd)
496 self.assert_called_anytime(
497 'POST', '/servers',
498 {
499 'server': {
500 'flavorRef': '1',
501 'name': 'some-server',
502 'imageRef': '1',
503 'min_count': 1,
504 'max_count': 1,
505 'networks': [
506 {'uuid': 'a=c', 'fixed_ip': '2001:db9:0:1::10'},
507 ],
508 },
509 },
510 )
511
512 def test_boot_nics_both_ipv4_and_ipv6(self):
513 cmd = ('boot --image 1 --flavor 1 '
514 '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,'
515 'v6-fixed-ip=2001:db9:0:1::10 some-server')
516 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
517
518 def test_boot_nics_no_value(self):
519 cmd = ('boot --image 1 --flavor 1 '
520 '--nic net-id some-server')
521 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
522
523 def test_boot_nics_random_key(self):
524 cmd = ('boot --image 1 --flavor 1 '
525 '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,foo=bar some-server')
526 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
527
528 def test_boot_nics_no_netid_or_portid(self):
529 cmd = ('boot --image 1 --flavor 1 '
530 '--nic v4-fixed-ip=10.0.0.1 some-server')
531 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
532
533 def test_boot_nics_netid_and_portid(self):
534 cmd = ('boot --image 1 --flavor 1 '
535 '--nic port-id=some=port,net-id=some=net some-server')
536 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
537
538 def test_boot_files(self):
539 testfile = os.path.join(os.path.dirname(__file__), 'testfile.txt')
540 data = open(testfile).read()
541 expected = base64.b64encode(data.encode('utf-8')).decode('utf-8')
542
543 cmd = ('boot some-server --flavor 1 --image 1'
544 ' --file /tmp/foo=%s --file /tmp/bar=%s')
545 self.run_command(cmd % (testfile, testfile))
546
547 self.assert_called_anytime(
548 'POST', '/servers',
549 {'server': {
550 'flavorRef': '1',
551 'name': 'some-server',
552 'imageRef': '1',
553 'min_count': 1,
554 'max_count': 1,
555 'personality': [
556 {'path': '/tmp/bar', 'contents': expected},
557 {'path': '/tmp/foo', 'contents': expected},
558 ]
559 }},
560 )
561
562 def test_boot_invalid_files(self):
563 invalid_file = os.path.join(os.path.dirname(__file__),
564 'asdfasdfasdfasdf')
565 cmd = ('boot some-server --flavor 1 --image 1'
566 ' --file /foo=%s' % invalid_file)
567 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
568
569 def test_boot_num_instances(self):
570 self.run_command('boot --image 1 --flavor 1 --num-instances 3 server')
571 self.assert_called_anytime(
572 'POST', '/servers',
573 {
574 'server': {
575 'flavorRef': '1',
576 'name': 'server',
577 'imageRef': '1',
578 'min_count': 1,
579 'max_count': 3,
580 }
581 })
582
583 def test_boot_invalid_num_instances(self):
584 cmd = 'boot --image 1 --flavor 1 --num-instances 0 server'
585 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
586
587 def test_boot_num_instances_and_count(self):
588 cmd = 'boot --image 1 --flavor 1 --num-instances 3 --min-count 3 serv'
589 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
590 cmd = 'boot --image 1 --flavor 1 --num-instances 3 --max-count 3 serv'
591 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
592
593 def test_boot_min_max_count(self):
594 self.run_command('boot --image 1 --flavor 1 --max-count 3 server')
595 self.assert_called_anytime(
596 'POST', '/servers',
597 {
598 'server': {
599 'flavorRef': '1',
600 'name': 'server',
601 'imageRef': '1',
602 'min_count': 1,
603 'max_count': 3,
604 }
605 })
606 self.run_command('boot --image 1 --flavor 1 --min-count 3 server')
607 self.assert_called_anytime(
608 'POST', '/servers',
609 {
610 'server': {
611 'flavorRef': '1',
612 'name': 'server',
613 'imageRef': '1',
614 'min_count': 3,
615 'max_count': 3,
616 }
617 })
618 self.run_command('boot --image 1 --flavor 1 '
619 '--min-count 3 --max-count 3 server')
620 self.assert_called_anytime(
621 'POST', '/servers',
622 {
623 'server': {
624 'flavorRef': '1',
625 'name': 'server',
626 'imageRef': '1',
627 'min_count': 3,
628 'max_count': 3,
629 }
630 })
631 self.run_command('boot --image 1 --flavor 1 '
632 '--min-count 3 --max-count 5 server')
633 self.assert_called_anytime(
634 'POST', '/servers',
635 {
636 'server': {
637 'flavorRef': '1',
638 'name': 'server',
639 'imageRef': '1',
640 'min_count': 3,
641 'max_count': 5,
642 }
643 })
644 cmd = 'boot --image 1 --flavor 1 --min-count 3 --max-count 1 serv'
645 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
646
647 @mock.patch('novaclient.v2.shell._poll_for_status')
648 def test_boot_with_poll(self, poll_method):
649 self.run_command('boot --flavor 1 --image 1 some-server --poll')
650 self.assert_called_anytime(
651 'POST', '/servers',
652 {'server': {
653 'flavorRef': '1',
654 'name': 'some-server',
655 'imageRef': '1',
656 'min_count': 1,
657 'max_count': 1,
658 }},
659 )
660 self.assertEqual(1, poll_method.call_count)
661 poll_method.assert_has_calls(
662 [mock.call(self.shell.cs.servers.get, 1234, 'building',
663 ['active'])])
664
665 def test_boot_with_poll_to_check_VM_state_error(self):
666 self.assertRaises(exceptions.InstanceInErrorState, self.run_command,
667 'boot --flavor 1 --image 1 some-bad-server --poll')
668
669 def test_boot_named_flavor(self):
670 self.run_command(["boot", "--image", "1",
671 "--flavor", "512 MB Server",
672 "--max-count", "3", "server"])
673 self.assert_called('GET', '/images/1', pos=0)
674 self.assert_called('GET', '/flavors/512 MB Server', pos=1)
675 self.assert_called('GET', '/flavors?is_public=None', pos=2)
676 self.assert_called('GET', '/flavors?is_public=None', pos=3)
677 self.assert_called('GET', '/flavors/2', pos=4)
678 self.assert_called(
679 'POST', '/servers',
680 {
681 'server': {
682 'flavorRef': '2',
683 'name': 'server',
684 'imageRef': '1',
685 'min_count': 1,
686 'max_count': 3,
687 }
688 }, pos=5)
689
690 def test_flavor_list(self):
691 self.run_command('flavor-list')
692 self.assert_called_anytime('GET', '/flavors/detail')
693
694 def test_flavor_list_with_extra_specs(self):
695 self.run_command('flavor-list --extra-specs')
696 self.assert_called('GET', '/flavors/aa1/os-extra_specs')
697 self.assert_called_anytime('GET', '/flavors/detail')
698
699 def test_flavor_list_with_all(self):
700 self.run_command('flavor-list --all')
701 self.assert_called('GET', '/flavors/detail?is_public=None')
702
703 def test_flavor_show(self):
704 self.run_command('flavor-show 1')
705 self.assert_called_anytime('GET', '/flavors/1')
706
707 def test_flavor_show_with_alphanum_id(self):
708 self.run_command('flavor-show aa1')
709 self.assert_called_anytime('GET', '/flavors/aa1')
710
711 def test_flavor_show_by_name(self):
712 self.run_command(['flavor-show', '128 MB Server'])
713 self.assert_called('GET', '/flavors/128 MB Server', pos=0)
714 self.assert_called('GET', '/flavors?is_public=None', pos=1)
715 self.assert_called('GET', '/flavors?is_public=None', pos=2)
716 self.assert_called('GET', '/flavors/aa1', pos=3)
717 self.assert_called('GET', '/flavors/aa1/os-extra_specs', pos=4)
718
719 def test_flavor_show_by_name_priv(self):
720 self.run_command(['flavor-show', '512 MB Server'])
721 self.assert_called('GET', '/flavors/512 MB Server', pos=0)
722 self.assert_called('GET', '/flavors?is_public=None', pos=1)
723 self.assert_called('GET', '/flavors?is_public=None', pos=2)
724 self.assert_called('GET', '/flavors/2', pos=3)
725 self.assert_called('GET', '/flavors/2/os-extra_specs', pos=4)
726
727 def test_flavor_key_set(self):
728 self.run_command('flavor-key 1 set k1=v1')
729 self.assert_called('POST', '/flavors/1/os-extra_specs',
730 {'extra_specs': {'k1': 'v1'}})
731
732 def test_flavor_key_unset(self):
733 self.run_command('flavor-key 1 unset k1')
734 self.assert_called('DELETE', '/flavors/1/os-extra_specs/k1')
735
736 def test_flavor_access_list_flavor(self):
737 self.run_command('flavor-access-list --flavor 2')
738 self.assert_called('GET', '/flavors/2/os-flavor-access')
739
740 # FIXME: flavor-access-list is not implemented yet
741 # def test_flavor_access_list_tenant(self):
742 # self.run_command('flavor-access-list --tenant proj2')
743 # self.assert_called('GET', '/flavors/2/os-flavor-access')
744
745 def test_flavor_access_list_bad_filter(self):
746 cmd = 'flavor-access-list --flavor 2 --tenant proj2'
747 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
748
749 def test_flavor_access_list_no_filter(self):
750 cmd = 'flavor-access-list'
751 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
752
753 def test_flavor_access_add_by_id(self):
754 self.run_command('flavor-access-add 2 proj2')
755 self.assert_called('POST', '/flavors/2/action',
756 {'addTenantAccess': {'tenant': 'proj2'}})
757
758 def test_flavor_access_add_by_name(self):
759 self.run_command(['flavor-access-add', '512 MB Server', 'proj2'])
760 self.assert_called('POST', '/flavors/2/action',
761 {'addTenantAccess': {'tenant': 'proj2'}})
762
763 def test_flavor_access_remove_by_id(self):
764 self.run_command('flavor-access-remove 2 proj2')
765 self.assert_called('POST', '/flavors/2/action',
766 {'removeTenantAccess': {'tenant': 'proj2'}})
767
768 def test_flavor_access_remove_by_name(self):
769 self.run_command(['flavor-access-remove', '512 MB Server', 'proj2'])
770 self.assert_called('POST', '/flavors/2/action',
771 {'removeTenantAccess': {'tenant': 'proj2'}})
772
773 def test_image_show(self):
774 self.run_command('image-show 1')
775 self.assert_called('GET', '/images/1')
776
777 def test_image_meta_set(self):
778 self.run_command('image-meta 1 set test_key=test_value')
779 self.assert_called('POST', '/images/1/metadata',
780 {'metadata': {'test_key': 'test_value'}})
781
782 def test_image_meta_del(self):
783 self.run_command('image-meta 1 delete test_key=test_value')
784 self.assert_called('DELETE', '/images/1/metadata/test_key')
785
786 @mock.patch('sys.stdout', six.StringIO())
787 @mock.patch('sys.stderr', six.StringIO())
788 def test_image_meta_bad_action(self):
789 self.assertRaises(SystemExit, self.run_command,
790 'image-meta 1 BAD_ACTION test_key=test_value')
791
792 def test_image_list(self):
793 self.run_command('image-list')
794 self.assert_called('GET', '/images/detail')
795
796 def test_create_image(self):
797 self.run_command('image-create sample-server mysnapshot')
798 self.assert_called(
799 'POST', '/servers/1234/action',
800 {'createImage': {'name': 'mysnapshot', 'metadata': {}}},
801 )
802
803 def test_create_image_show(self):
804 output = self.run_command(
805 'image-create sample-server mysnapshot --show')
806 self.assert_called_anytime(
807 'POST', '/servers/1234/action',
808 {'createImage': {'name': 'mysnapshot', 'metadata': {}}},
809 )
810 self.assertIn('My Server Backup', output)
811 self.assertIn('SAVING', output)
812
813 def test_image_delete(self):
814 self.run_command('image-delete 1')
815 self.assert_called('DELETE', '/images/1')
816
817 def test_image_delete_multiple(self):
818 self.run_command('image-delete 1 2')
819 self.assert_called('DELETE', '/images/1', pos=-3)
820 self.assert_called('DELETE', '/images/2', pos=-1)
821
822 def test_list(self):
823 self.run_command('list')
824 self.assert_called('GET', '/servers/detail')
825
826 def test_list_minimal(self):
827 self.run_command('list --minimal')
828 self.assert_called('GET', '/servers')
829
830 def test_list_deleted(self):
831 self.run_command('list --deleted')
832 self.assert_called('GET', '/servers/detail?deleted=True')
833
834 def test_list_with_images(self):
835 self.run_command('list --image 1')
836 self.assert_called('GET', '/servers/detail?image=1')
837
838 def test_list_with_flavors(self):
839 self.run_command('list --flavor 1')
840 self.assert_called('GET', '/servers/detail?flavor=1')
841
842 def test_list_by_tenant(self):
843 self.run_command('list --tenant fake_tenant')
844 self.assert_called(
845 'GET',
846 '/servers/detail?all_tenants=1&tenant_id=fake_tenant')
847
848 def test_list_by_user(self):
849 self.run_command('list --user fake_user')
850 self.assert_called(
851 'GET',
852 '/servers/detail?all_tenants=1&user_id=fake_user')
853
854 def test_list_with_single_sort_key_no_dir(self):
855 self.run_command('list --sort 1')
856 self.assert_called(
857 'GET', ('/servers/detail?sort_dir=desc&sort_key=1'))
858
859 def test_list_with_single_sort_key_and_dir(self):
860 self.run_command('list --sort 1:asc')
861 self.assert_called(
862 'GET', ('/servers/detail?sort_dir=asc&sort_key=1'))
863
864 def test_list_with_sort_keys_no_dir(self):
865 self.run_command('list --sort 1,2')
866 self.assert_called(
867 'GET', ('/servers/detail?sort_dir=desc&sort_dir=desc&'
868 'sort_key=1&sort_key=2'))
869
870 def test_list_with_sort_keys_and_dirs(self):
871 self.run_command('list --sort 1:asc,2:desc')
872 self.assert_called(
873 'GET', ('/servers/detail?sort_dir=asc&sort_dir=desc&'
874 'sort_key=1&sort_key=2'))
875
876 def test_list_with_sort_keys_and_some_dirs(self):
877 self.run_command('list --sort 1,2:asc')
878 self.assert_called(
879 'GET', ('/servers/detail?sort_dir=desc&sort_dir=asc&'
880 'sort_key=1&sort_key=2'))
881
882 def test_list_with_invalid_sort_dir_one(self):
883 cmd = 'list --sort 1:foo'
884 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
885
886 def test_list_with_invalid_sort_dir_two(self):
887 cmd = 'list --sort 1:asc,2:foo'
888 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
889
890 def test_list_sortby_index_with_sort(self):
891 # sortby_index is None if there is sort information
892 for cmd in ['list --sort key',
893 'list --sort key:desc',
894 'list --sort key1,key2:asc']:
895 with mock.patch('novaclient.utils.print_list') as mock_print_list:
896 self.run_command(cmd)
897 mock_print_list.assert_called_once_with(
898 mock.ANY, mock.ANY, mock.ANY, sortby_index=None)
899
900 def test_list_sortby_index_without_sort(self):
901 # sortby_index is 1 without sort information
902 for cmd in ['list', 'list --minimal', 'list --deleted']:
903 with mock.patch('novaclient.utils.print_list') as mock_print_list:
904 self.run_command(cmd)
905 mock_print_list.assert_called_once_with(
906 mock.ANY, mock.ANY, mock.ANY, sortby_index=1)
907
908 def test_list_fields(self):
909 output = self.run_command(
910 'list --fields '
911 'host,security_groups,OS-EXT-MOD:some_thing')
912 self.assert_called('GET', '/servers/detail')
913 self.assertIn('computenode1', output)
914 self.assertIn('securitygroup1', output)
915 self.assertIn('OS-EXT-MOD: Some Thing', output)
916 self.assertIn('mod_some_thing_value', output)
917
918 def test_reboot(self):
919 self.run_command('reboot sample-server')
920 self.assert_called('POST', '/servers/1234/action',
921 {'reboot': {'type': 'SOFT'}})
922 self.run_command('reboot sample-server --hard')
923 self.assert_called('POST', '/servers/1234/action',
924 {'reboot': {'type': 'HARD'}})
925
926 def test_rebuild(self):
927 output = self.run_command('rebuild sample-server 1')
928 self.assert_called('GET', '/servers?name=sample-server', pos=-6)
929 self.assert_called('GET', '/servers/1234', pos=-5)
930 self.assert_called('GET', '/images/1', pos=-4)
931 self.assert_called('POST', '/servers/1234/action',
932 {'rebuild': {'imageRef': 1}}, pos=-3)
933 self.assert_called('GET', '/flavors/1', pos=-2)
934 self.assert_called('GET', '/images/2')
935 self.assertIn('adminPass', output)
936
937 def test_rebuild_password(self):
938 output = self.run_command('rebuild sample-server 1'
939 ' --rebuild-password asdf')
940 self.assert_called('GET', '/servers?name=sample-server', pos=-6)
941 self.assert_called('GET', '/servers/1234', pos=-5)
942 self.assert_called('GET', '/images/1', pos=-4)
943 self.assert_called('POST', '/servers/1234/action',
944 {'rebuild': {'imageRef': 1, 'adminPass': 'asdf'}},
945 pos=-3)
946 self.assert_called('GET', '/flavors/1', pos=-2)
947 self.assert_called('GET', '/images/2')
948 self.assertIn('adminPass', output)
949
950 def test_rebuild_preserve_ephemeral(self):
951 self.run_command('rebuild sample-server 1 --preserve-ephemeral')
952 self.assert_called('GET', '/servers?name=sample-server', pos=-6)
953 self.assert_called('GET', '/servers/1234', pos=-5)
954 self.assert_called('GET', '/images/1', pos=-4)
955 self.assert_called('POST', '/servers/1234/action',
956 {'rebuild': {'imageRef': 1,
957 'preserve_ephemeral': True}}, pos=-3)
958 self.assert_called('GET', '/flavors/1', pos=-2)
959 self.assert_called('GET', '/images/2')
960
961 def test_rebuild_name_meta(self):
962 self.run_command('rebuild sample-server 1 --name asdf --meta '
963 'foo=bar')
964 self.assert_called('GET', '/servers?name=sample-server', pos=-6)
965 self.assert_called('GET', '/servers/1234', pos=-5)
966 self.assert_called('GET', '/images/1', pos=-4)
967 self.assert_called('POST', '/servers/1234/action',
968 {'rebuild': {'imageRef': 1,
969 'name': 'asdf',
970 'metadata': {'foo': 'bar'}}}, pos=-3)
971 self.assert_called('GET', '/flavors/1', pos=-2)
972 self.assert_called('GET', '/images/2')
973
974 def test_start(self):
975 self.run_command('start sample-server')
976 self.assert_called('POST', '/servers/1234/action', {'os-start': None})
977
978 def test_stop(self):
979 self.run_command('stop sample-server')
980 self.assert_called('POST', '/servers/1234/action', {'os-stop': None})
981
982 def test_pause(self):
983 self.run_command('pause sample-server')
984 self.assert_called('POST', '/servers/1234/action', {'pause': None})
985
986 def test_unpause(self):
987 self.run_command('unpause sample-server')
988 self.assert_called('POST', '/servers/1234/action', {'unpause': None})
989
990 def test_lock(self):
991 self.run_command('lock sample-server')
992 self.assert_called('POST', '/servers/1234/action', {'lock': None})
993
994 def test_unlock(self):
995 self.run_command('unlock sample-server')
996 self.assert_called('POST', '/servers/1234/action', {'unlock': None})
997
998 def test_suspend(self):
999 self.run_command('suspend sample-server')
1000 self.assert_called('POST', '/servers/1234/action', {'suspend': None})
1001
1002 def test_resume(self):
1003 self.run_command('resume sample-server')
1004 self.assert_called('POST', '/servers/1234/action', {'resume': None})
1005
1006 def test_rescue(self):
1007 self.run_command('rescue sample-server')
1008 self.assert_called('POST', '/servers/1234/action', {'rescue': None})
1009
1010 def test_rescue_password(self):
1011 self.run_command('rescue sample-server --password asdf')
1012 self.assert_called('POST', '/servers/1234/action',
1013 {'rescue': {'adminPass': 'asdf'}})
1014
1015 def test_rescue_image(self):
1016 self.run_command('rescue sample-server --image 1')
1017 self.assert_called('POST', '/servers/1234/action',
1018 {'rescue': {'rescue_image_ref': 1}})
1019
1020 def test_unrescue(self):
1021 self.run_command('unrescue sample-server')
1022 self.assert_called('POST', '/servers/1234/action', {'unrescue': None})
1023
1024 def test_shelve(self):
1025 self.run_command('shelve sample-server')
1026 self.assert_called('POST', '/servers/1234/action', {'shelve': None})
1027
1028 def test_shelve_offload(self):
1029 self.run_command('shelve-offload sample-server')
1030 self.assert_called('POST', '/servers/1234/action',
1031 {'shelveOffload': None})
1032
1033 def test_unshelve(self):
1034 self.run_command('unshelve sample-server')
1035 self.assert_called('POST', '/servers/1234/action', {'unshelve': None})
1036
1037 def test_migrate(self):
1038 self.run_command('migrate sample-server')
1039 self.assert_called('POST', '/servers/1234/action', {'migrate': None})
1040
1041 def test_rename(self):
1042 self.run_command('rename sample-server newname')
1043 self.assert_called('PUT', '/servers/1234',
1044 {'server': {'name': 'newname'}})
1045
1046 def test_resize(self):
1047 self.run_command('resize sample-server 1')
1048 self.assert_called('POST', '/servers/1234/action',
1049 {'resize': {'flavorRef': 1}})
1050
1051 def test_resize_confirm(self):
1052 self.run_command('resize-confirm sample-server')
1053 self.assert_called('POST', '/servers/1234/action',
1054 {'confirmResize': None})
1055
1056 def test_resize_revert(self):
1057 self.run_command('resize-revert sample-server')
1058 self.assert_called('POST', '/servers/1234/action',
1059 {'revertResize': None})
1060
1061 @mock.patch('getpass.getpass', mock.Mock(return_value='p'))
1062 def test_root_password(self):
1063 self.run_command('root-password sample-server')
1064 self.assert_called('POST', '/servers/1234/action',
1065 {'changePassword': {'adminPass': 'p'}})
1066
1067 def test_scrub(self):
1068 self.run_command('scrub 4ffc664c198e435e9853f2538fbcd7a7')
1069 self.assert_called('GET', '/os-networks', pos=-4)
1070 self.assert_called('GET', '/os-security-groups?all_tenants=1',
1071 pos=-3)
1072 self.assert_called('POST', '/os-networks/1/action',
1073 {"disassociate": None}, pos=-2)
1074 self.assert_called('DELETE', '/os-security-groups/1')
1075
1076 def test_show(self):
1077 self.run_command('show 1234')
1078 self.assert_called('GET', '/servers/1234', pos=-3)
1079 self.assert_called('GET', '/flavors/1', pos=-2)
1080 self.assert_called('GET', '/images/2')
1081
1082 def test_show_no_image(self):
1083 self.run_command('show 9012')
1084 self.assert_called('GET', '/servers/9012', pos=-2)
1085 self.assert_called('GET', '/flavors/1', pos=-1)
1086
1087 def test_show_bad_id(self):
1088 self.assertRaises(exceptions.CommandError,
1089 self.run_command, 'show xxx')
1090
1091 @mock.patch('novaclient.v2.shell.utils.print_dict')
1092 def test_print_server(self, mock_print_dict):
1093 self.run_command('show 5678')
1094 args, kwargs = mock_print_dict.call_args
1095 parsed_server = args[0]
1096 self.assertEqual('securitygroup1, securitygroup2',
1097 parsed_server['security_groups'])
1098
1099 def test_delete(self):
1100 self.run_command('delete 1234')
1101 self.assert_called('DELETE', '/servers/1234')
1102 self.run_command('delete sample-server')
1103 self.assert_called('DELETE', '/servers/1234')
1104
1105 def test_force_delete(self):
1106 self.run_command('force-delete 1234')
1107 self.assert_called('POST', '/servers/1234/action',
1108 {'forceDelete': None})
1109 self.run_command('force-delete sample-server')
1110 self.assert_called('POST', '/servers/1234/action',
1111 {'forceDelete': None})
1112
1113 def test_restore(self):
1114 self.run_command('restore 1234')
1115 self.assert_called('POST', '/servers/1234/action', {'restore': None})
1116 self.run_command('restore sample-server')
1117 self.assert_called('POST', '/servers/1234/action', {'restore': None})
1118
1119 def test_delete_two_with_two_existent(self):
1120 self.run_command('delete 1234 5678')
1121 self.assert_called('DELETE', '/servers/1234', pos=-3)
1122 self.assert_called('DELETE', '/servers/5678', pos=-1)
1123 self.run_command('delete sample-server sample-server2')
1124 self.assert_called('GET', '/servers?name=sample-server', pos=-6)
1125 self.assert_called('GET', '/servers/1234', pos=-5)
1126 self.assert_called('DELETE', '/servers/1234', pos=-4)
1127 self.assert_called('GET', '/servers?name=sample-server2', pos=-3)
1128 self.assert_called('GET', '/servers/5678', pos=-2)
1129 self.assert_called('DELETE', '/servers/5678', pos=-1)
1130
1131 def test_delete_two_with_one_nonexistent(self):
1132 cmd = 'delete 1234 123456789'
1133 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1134 self.assert_called_anytime('DELETE', '/servers/1234')
1135 cmd = 'delete sample-server nonexistentserver'
1136 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1137 self.assert_called_anytime('DELETE', '/servers/1234')
1138
1139 def test_delete_one_with_one_nonexistent(self):
1140 cmd = 'delete 123456789'
1141 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1142 cmd = 'delete nonexistent-server1'
1143 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1144
1145 def test_delete_two_with_two_nonexistent(self):
1146 cmd = 'delete 123456789 987654321'
1147 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1148 cmd = 'delete nonexistent-server1 nonexistent-server2'
1149 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1150
1151 def test_diagnostics(self):
1152 self.run_command('diagnostics 1234')
1153 self.assert_called('GET', '/servers/1234/diagnostics')
1154 self.run_command('diagnostics sample-server')
1155 self.assert_called('GET', '/servers/1234/diagnostics')
1156
1157 def test_refresh_network(self):
1158 self.run_command('refresh-network 1234')
1159 self.assert_called('POST', '/os-server-external-events',
1160 {'events': [{'name': 'network-changed',
1161 'server_uuid': 1234}]})
1162
1163 def test_set_meta_set(self):
1164 self.run_command('meta 1234 set key1=val1 key2=val2')
1165 self.assert_called('POST', '/servers/1234/metadata',
1166 {'metadata': {'key1': 'val1', 'key2': 'val2'}})
1167
1168 def test_set_meta_delete_dict(self):
1169 self.run_command('meta 1234 delete key1=val1 key2=val2')
1170 self.assert_called('DELETE', '/servers/1234/metadata/key1')
1171 self.assert_called('DELETE', '/servers/1234/metadata/key2', pos=-2)
1172
1173 def test_set_meta_delete_keys(self):
1174 self.run_command('meta 1234 delete key1 key2')
1175 self.assert_called('DELETE', '/servers/1234/metadata/key1')
1176 self.assert_called('DELETE', '/servers/1234/metadata/key2', pos=-2)
1177
1178 def test_set_host_meta(self):
1179 self.run_command('host-meta hyper set key1=val1 key2=val2')
1180 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1181 self.assert_called('POST', '/servers/uuid1/metadata',
1182 {'metadata': {'key1': 'val1', 'key2': 'val2'}},
1183 pos=1)
1184 self.assert_called('POST', '/servers/uuid2/metadata',
1185 {'metadata': {'key1': 'val1', 'key2': 'val2'}},
1186 pos=2)
1187 self.assert_called('POST', '/servers/uuid3/metadata',
1188 {'metadata': {'key1': 'val1', 'key2': 'val2'}},
1189 pos=3)
1190 self.assert_called('POST', '/servers/uuid4/metadata',
1191 {'metadata': {'key1': 'val1', 'key2': 'val2'}},
1192 pos=4)
1193
1194 def test_set_host_meta_with_no_servers(self):
1195 self.run_command('host-meta hyper_no_servers set key1=val1 key2=val2')
1196 self.assert_called('GET', '/os-hypervisors/hyper_no_servers/servers')
1197
1198 def test_delete_host_meta(self):
1199 self.run_command('host-meta hyper delete key1')
1200 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1201 self.assert_called('DELETE', '/servers/uuid1/metadata/key1', pos=1)
1202 self.assert_called('DELETE', '/servers/uuid2/metadata/key1', pos=2)
1203
1204 def test_dns_create(self):
1205 self.run_command('dns-create 192.168.1.1 testname testdomain')
1206 self.assert_called('PUT',
1207 '/os-floating-ip-dns/testdomain/entries/testname')
1208
1209 self.run_command('dns-create 192.168.1.1 testname testdomain --type A')
1210 self.assert_called('PUT',
1211 '/os-floating-ip-dns/testdomain/entries/testname')
1212
1213 def test_dns_create_public_domain(self):
1214 self.run_command('dns-create-public-domain testdomain '
1215 '--project test_project')
1216 self.assert_called('PUT', '/os-floating-ip-dns/testdomain')
1217
1218 def test_dns_create_private_domain(self):
1219 self.run_command('dns-create-private-domain testdomain '
1220 '--availability-zone av_zone')
1221 self.assert_called('PUT', '/os-floating-ip-dns/testdomain')
1222
1223 def test_dns_delete(self):
1224 self.run_command('dns-delete testdomain testname')
1225 self.assert_called('DELETE',
1226 '/os-floating-ip-dns/testdomain/entries/testname')
1227
1228 def test_dns_delete_domain(self):
1229 self.run_command('dns-delete-domain testdomain')
1230 self.assert_called('DELETE', '/os-floating-ip-dns/testdomain')
1231
1232 def test_dns_list(self):
1233 self.run_command('dns-list testdomain --ip 192.168.1.1')
1234 self.assert_called('GET',
1235 '/os-floating-ip-dns/testdomain/entries?'
1236 'ip=192.168.1.1')
1237
1238 self.run_command('dns-list testdomain --name testname')
1239 self.assert_called('GET',
1240 '/os-floating-ip-dns/testdomain/entries/testname')
1241
1242 def test_dns_domains(self):
1243 self.run_command('dns-domains')
1244 self.assert_called('GET', '/os-floating-ip-dns')
1245
1246 def test_floating_ip_list(self):
1247 self.run_command('floating-ip-list')
1248 self.assert_called('GET', '/os-floating-ips')
1249
1250 def test_floating_ip_list_all_tenants(self):
1251 self.run_command('floating-ip-list --all-tenants')
1252 self.assert_called('GET', '/os-floating-ips?all_tenants=1')
1253
1254 def test_floating_ip_create(self):
1255 self.run_command('floating-ip-create')
1256 self.assert_called('GET', '/os-floating-ips/1')
1257
1258 def test_floating_ip_delete(self):
1259 self.run_command('floating-ip-delete 11.0.0.1')
1260 self.assert_called('DELETE', '/os-floating-ips/1')
1261
1262 def test_floating_ip_bulk_list(self):
1263 self.run_command('floating-ip-bulk-list')
1264 self.assert_called('GET', '/os-floating-ips-bulk')
1265
1266 def test_floating_ip_bulk_create(self):
1267 self.run_command('floating-ip-bulk-create 10.0.0.1/24')
1268 self.assert_called('POST', '/os-floating-ips-bulk',
1269 {'floating_ips_bulk_create':
1270 {'ip_range': '10.0.0.1/24'}})
1271
1272 def test_floating_ip_bulk_create_host_and_interface(self):
1273 self.run_command('floating-ip-bulk-create 10.0.0.1/24 --pool testPool'
1274 ' --interface ethX')
1275 self.assert_called('POST', '/os-floating-ips-bulk',
1276 {'floating_ips_bulk_create':
1277 {'ip_range': '10.0.0.1/24',
1278 'pool': 'testPool',
1279 'interface': 'ethX'}})
1280
1281 def test_floating_ip_bulk_delete(self):
1282 self.run_command('floating-ip-bulk-delete 10.0.0.1/24')
1283 self.assert_called('PUT', '/os-floating-ips-bulk/delete',
1284 {'ip_range': '10.0.0.1/24'})
1285
1286 def test_server_floating_ip_add(self):
1287 self.run_command('add-floating-ip sample-server 11.0.0.1')
1288 self.assert_called('POST', '/servers/1234/action',
1289 {'addFloatingIp': {'address': '11.0.0.1'}})
1290
1291 def test_server_floating_ip_remove(self):
1292 self.run_command('remove-floating-ip sample-server 11.0.0.1')
1293 self.assert_called('POST', '/servers/1234/action',
1294 {'removeFloatingIp': {'address': '11.0.0.1'}})
1295
1296 def test_server_floating_ip_associate(self):
1297 self.run_command('floating-ip-associate sample-server 11.0.0.1')
1298 self.assert_called('POST', '/servers/1234/action',
1299 {'addFloatingIp': {'address': '11.0.0.1'}})
1300
1301 def test_server_floating_ip_disassociate(self):
1302 self.run_command('floating-ip-disassociate sample-server 11.0.0.1')
1303 self.assert_called('POST', '/servers/1234/action',
1304 {'removeFloatingIp': {'address': '11.0.0.1'}})
1305
1306 def test_usage_list(self):
1307 self.run_command('usage-list --start 2000-01-20 --end 2005-02-01')
1308 self.assert_called('GET',
1309 '/os-simple-tenant-usage?' +
1310 'start=2000-01-20T00:00:00&' +
1311 'end=2005-02-01T00:00:00&' +
1312 'detailed=1')
1313
1314 def test_usage_list_no_args(self):
1315 timeutils.set_time_override(datetime.datetime(2005, 2, 1, 0, 0))
1316 self.addCleanup(timeutils.clear_time_override)
1317 self.run_command('usage-list')
1318 self.assert_called('GET',
1319 '/os-simple-tenant-usage?' +
1320 'start=2005-01-04T00:00:00&' +
1321 'end=2005-02-02T00:00:00&' +
1322 'detailed=1')
1323
1324 def test_usage(self):
1325 self.run_command('usage --start 2000-01-20 --end 2005-02-01 '
1326 '--tenant test')
1327 self.assert_called('GET',
1328 '/os-simple-tenant-usage/test?' +
1329 'start=2000-01-20T00:00:00&' +
1330 'end=2005-02-01T00:00:00')
1331
1332 def test_usage_no_tenant(self):
1333 self.run_command('usage --start 2000-01-20 --end 2005-02-01')
1334 self.assert_called('GET',
1335 '/os-simple-tenant-usage/tenant_id?' +
1336 'start=2000-01-20T00:00:00&' +
1337 'end=2005-02-01T00:00:00')
1338
1339 def test_flavor_delete(self):
1340 self.run_command("flavor-delete 2")
1341 self.assert_called('DELETE', '/flavors/2')
1342
1343 def test_flavor_create(self):
1344 self.run_command("flavor-create flavorcreate "
1345 "1234 512 10 1 --swap 1024 --ephemeral 10 "
1346 "--is-public true")
1347 self.assert_called('POST', '/flavors', pos=-2)
1348 self.assert_called('GET', '/flavors/1', pos=-1)
1349
1350 def test_aggregate_list(self):
1351 self.run_command('aggregate-list')
1352 self.assert_called('GET', '/os-aggregates')
1353
1354 def test_aggregate_create(self):
1355 self.run_command('aggregate-create test_name nova1')
1356 body = {"aggregate": {"name": "test_name",
1357 "availability_zone": "nova1"}}
1358 self.assert_called('POST', '/os-aggregates', body, pos=-2)
1359 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1360
1361 def test_aggregate_delete_by_id(self):
1362 self.run_command('aggregate-delete 1')
1363 self.assert_called('DELETE', '/os-aggregates/1')
1364
1365 def test_aggregate_delete_by_name(self):
1366 self.run_command('aggregate-delete test')
1367 self.assert_called('DELETE', '/os-aggregates/1')
1368
1369 def test_aggregate_update_by_id(self):
1370 self.run_command('aggregate-update 1 new_name')
1371 body = {"aggregate": {"name": "new_name"}}
1372 self.assert_called('PUT', '/os-aggregates/1', body, pos=-2)
1373 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1374
1375 def test_aggregate_update_by_name(self):
1376 self.run_command('aggregate-update test new_name')
1377 body = {"aggregate": {"name": "new_name"}}
1378 self.assert_called('PUT', '/os-aggregates/1', body, pos=-2)
1379 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1380
1381 def test_aggregate_update_with_availability_zone_by_id(self):
1382 self.run_command('aggregate-update 1 foo new_zone')
1383 body = {"aggregate": {"name": "foo", "availability_zone": "new_zone"}}
1384 self.assert_called('PUT', '/os-aggregates/1', body, pos=-2)
1385 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1386
1387 def test_aggregate_update_with_availability_zone_by_name(self):
1388 self.run_command('aggregate-update test foo new_zone')
1389 body = {"aggregate": {"name": "foo", "availability_zone": "new_zone"}}
1390 self.assert_called('PUT', '/os-aggregates/1', body, pos=-2)
1391 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1392
1393 def test_aggregate_set_metadata_add_by_id(self):
1394 self.run_command('aggregate-set-metadata 3 foo=bar')
1395 body = {"set_metadata": {"metadata": {"foo": "bar"}}}
1396 self.assert_called('POST', '/os-aggregates/3/action', body, pos=-2)
1397 self.assert_called('GET', '/os-aggregates/3', pos=-1)
1398
1399 def test_aggregate_set_metadata_add_duplicate_by_id(self):
1400 cmd = 'aggregate-set-metadata 3 test=dup'
1401 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1402
1403 def test_aggregate_set_metadata_delete_by_id(self):
1404 self.run_command('aggregate-set-metadata 3 none_key')
1405 body = {"set_metadata": {"metadata": {"none_key": None}}}
1406 self.assert_called('POST', '/os-aggregates/3/action', body, pos=-2)
1407 self.assert_called('GET', '/os-aggregates/3', pos=-1)
1408
1409 def test_aggregate_set_metadata_delete_missing_by_id(self):
1410 cmd = 'aggregate-set-metadata 3 delete_key2'
1411 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1412
1413 def test_aggregate_set_metadata_by_name(self):
1414 self.run_command('aggregate-set-metadata test foo=bar')
1415 body = {"set_metadata": {"metadata": {"foo": "bar"}}}
1416 self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
1417 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1418
1419 def test_aggregate_add_host_by_id(self):
1420 self.run_command('aggregate-add-host 1 host1')
1421 body = {"add_host": {"host": "host1"}}
1422 self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
1423 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1424
1425 def test_aggregate_add_host_by_name(self):
1426 self.run_command('aggregate-add-host test host1')
1427 body = {"add_host": {"host": "host1"}}
1428 self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
1429 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1430
1431 def test_aggregate_remove_host_by_id(self):
1432 self.run_command('aggregate-remove-host 1 host1')
1433 body = {"remove_host": {"host": "host1"}}
1434 self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
1435 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1436
1437 def test_aggregate_remove_host_by_name(self):
1438 self.run_command('aggregate-remove-host test host1')
1439 body = {"remove_host": {"host": "host1"}}
1440 self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
1441 self.assert_called('GET', '/os-aggregates/1', pos=-1)
1442
1443 def test_aggregate_details_by_id(self):
1444 self.run_command('aggregate-details 1')
1445 self.assert_called('GET', '/os-aggregates/1')
1446
1447 def test_aggregate_details_by_name(self):
1448 self.run_command('aggregate-details test')
1449 self.assert_called('GET', '/os-aggregates')
1450
1451 def test_live_migration(self):
1452 self.run_command('live-migration sample-server hostname')
1453 self.assert_called('POST', '/servers/1234/action',
1454 {'os-migrateLive': {'host': 'hostname',
1455 'block_migration': False,
1456 'disk_over_commit': False}})
1457 self.run_command('live-migration sample-server hostname'
1458 ' --block-migrate')
1459 self.assert_called('POST', '/servers/1234/action',
1460 {'os-migrateLive': {'host': 'hostname',
1461 'block_migration': True,
1462 'disk_over_commit': False}})
1463 self.run_command('live-migration sample-server hostname'
1464 ' --block-migrate --disk-over-commit')
1465 self.assert_called('POST', '/servers/1234/action',
1466 {'os-migrateLive': {'host': 'hostname',
1467 'block_migration': True,
1468 'disk_over_commit': True}})
1469
1470 def test_host_evacuate_live_with_no_target_host(self):
1471 self.run_command('host-evacuate-live hyper')
1472 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1473 body = {'os-migrateLive': {'host': None,
1474 'block_migration': False,
1475 'disk_over_commit': False}}
1476 self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
1477 self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
1478 self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
1479 self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
1480
1481 def test_host_evacuate_live_with_target_host(self):
1482 self.run_command('host-evacuate-live hyper '
1483 '--target-host hostname')
1484 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1485 body = {'os-migrateLive': {'host': 'hostname',
1486 'block_migration': False,
1487 'disk_over_commit': False}}
1488 self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
1489 self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
1490 self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
1491 self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
1492
1493 def test_host_evacuate_live_with_block_migration(self):
1494 self.run_command('host-evacuate-live --block-migrate hyper')
1495 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1496 body = {'os-migrateLive': {'host': None,
1497 'block_migration': True,
1498 'disk_over_commit': False}}
1499 self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
1500 self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
1501 self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
1502 self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
1503
1504 def test_host_evacuate_live_with_disk_over_commit(self):
1505 self.run_command('host-evacuate-live --disk-over-commit hyper')
1506 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1507 body = {'os-migrateLive': {'host': None,
1508 'block_migration': False,
1509 'disk_over_commit': True}}
1510 self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
1511 self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
1512 self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
1513 self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
1514
1515 def test_reset_state(self):
1516 self.run_command('reset-state sample-server')
1517 self.assert_called('POST', '/servers/1234/action',
1518 {'os-resetState': {'state': 'error'}})
1519 self.run_command('reset-state sample-server --active')
1520 self.assert_called('POST', '/servers/1234/action',
1521 {'os-resetState': {'state': 'active'}})
1522
1523 def test_reset_state_multiple(self):
1524 self.run_command('reset-state sample-server sample-server2')
1525 self.assert_called('POST', '/servers/1234/action',
1526 {'os-resetState': {'state': 'error'}}, pos=-4)
1527 self.assert_called('POST', '/servers/5678/action',
1528 {'os-resetState': {'state': 'error'}}, pos=-1)
1529
1530 def test_reset_state_active_multiple(self):
1531 self.run_command('reset-state --active sample-server sample-server2')
1532 self.assert_called('POST', '/servers/1234/action',
1533 {'os-resetState': {'state': 'active'}}, pos=-4)
1534 self.assert_called('POST', '/servers/5678/action',
1535 {'os-resetState': {'state': 'active'}}, pos=-1)
1536
1537 def test_reset_network(self):
1538 self.run_command('reset-network sample-server')
1539 self.assert_called('POST', '/servers/1234/action',
1540 {'resetNetwork': None})
1541
1542 def test_services_list(self):
1543 self.run_command('service-list')
1544 self.assert_called('GET', '/os-services')
1545
1546 def test_services_list_with_host(self):
1547 self.run_command('service-list --host host1')
1548 self.assert_called('GET', '/os-services?host=host1')
1549
1550 def test_services_list_with_binary(self):
1551 self.run_command('service-list --binary nova-cert')
1552 self.assert_called('GET', '/os-services?binary=nova-cert')
1553
1554 def test_services_list_with_host_binary(self):
1555 self.run_command('service-list --host host1 --binary nova-cert')
1556 self.assert_called('GET', '/os-services?host=host1&binary=nova-cert')
1557
1558 def test_services_enable(self):
1559 self.run_command('service-enable host1 nova-cert')
1560 body = {'host': 'host1', 'binary': 'nova-cert'}
1561 self.assert_called('PUT', '/os-services/enable', body)
1562
1563 def test_services_disable(self):
1564 self.run_command('service-disable host1 nova-cert')
1565 body = {'host': 'host1', 'binary': 'nova-cert'}
1566 self.assert_called('PUT', '/os-services/disable', body)
1567
1568 def test_services_disable_with_reason(self):
1569 self.run_command('service-disable host1 nova-cert --reason no_reason')
1570 body = {'host': 'host1', 'binary': 'nova-cert',
1571 'disabled_reason': 'no_reason'}
1572 self.assert_called('PUT', '/os-services/disable-log-reason', body)
1573
1574 def test_services_delete(self):
1575 self.run_command('service-delete 1')
1576 self.assert_called('DELETE', '/os-services/1')
1577
1578 def test_fixed_ips_get(self):
1579 self.run_command('fixed-ip-get 192.168.1.1')
1580 self.assert_called('GET', '/os-fixed-ips/192.168.1.1')
1581
1582 def test_fixed_ips_reserve(self):
1583 self.run_command('fixed-ip-reserve 192.168.1.1')
1584 body = {'reserve': None}
1585 self.assert_called('POST', '/os-fixed-ips/192.168.1.1/action', body)
1586
1587 def test_fixed_ips_unreserve(self):
1588 self.run_command('fixed-ip-unreserve 192.168.1.1')
1589 body = {'unreserve': None}
1590 self.assert_called('POST', '/os-fixed-ips/192.168.1.1/action', body)
1591
1592 def test_host_list(self):
1593 self.run_command('host-list')
1594 self.assert_called('GET', '/os-hosts')
1595
1596 def test_host_list_with_zone(self):
1597 self.run_command('host-list --zone nova')
1598 self.assert_called('GET', '/os-hosts?zone=nova')
1599
1600 def test_host_update_status(self):
1601 self.run_command('host-update sample-host_1 --status enabled')
1602 body = {'status': 'enabled'}
1603 self.assert_called('PUT', '/os-hosts/sample-host_1', body)
1604
1605 def test_host_update_maintenance(self):
1606 self.run_command('host-update sample-host_2 --maintenance enable')
1607 body = {'maintenance_mode': 'enable'}
1608 self.assert_called('PUT', '/os-hosts/sample-host_2', body)
1609
1610 def test_host_update_multiple_settings(self):
1611 self.run_command('host-update sample-host_3 '
1612 '--status disabled --maintenance enable')
1613 body = {'status': 'disabled', 'maintenance_mode': 'enable'}
1614 self.assert_called('PUT', '/os-hosts/sample-host_3', body)
1615
1616 def test_host_startup(self):
1617 self.run_command('host-action sample-host --action startup')
1618 self.assert_called(
1619 'GET', '/os-hosts/sample-host/startup')
1620
1621 def test_host_shutdown(self):
1622 self.run_command('host-action sample-host --action shutdown')
1623 self.assert_called(
1624 'GET', '/os-hosts/sample-host/shutdown')
1625
1626 def test_host_reboot(self):
1627 self.run_command('host-action sample-host --action reboot')
1628 self.assert_called(
1629 'GET', '/os-hosts/sample-host/reboot')
1630
1631 def test_host_evacuate(self):
1632 self.run_command('host-evacuate hyper --target target_hyper')
1633 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1634 self.assert_called('POST', '/servers/uuid1/action',
1635 {'evacuate': {'host': 'target_hyper',
1636 'onSharedStorage': False}}, pos=1)
1637 self.assert_called('POST', '/servers/uuid2/action',
1638 {'evacuate': {'host': 'target_hyper',
1639 'onSharedStorage': False}}, pos=2)
1640 self.assert_called('POST', '/servers/uuid3/action',
1641 {'evacuate': {'host': 'target_hyper',
1642 'onSharedStorage': False}}, pos=3)
1643 self.assert_called('POST', '/servers/uuid4/action',
1644 {'evacuate': {'host': 'target_hyper',
1645 'onSharedStorage': False}}, pos=4)
1646
1647 def test_host_evacuate_with_shared_storage(self):
1648 self.run_command(
1649 'host-evacuate --on-shared-storage hyper --target target_hyper')
1650 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1651 self.assert_called('POST', '/servers/uuid1/action',
1652 {'evacuate': {'host': 'target_hyper',
1653 'onSharedStorage': True}}, pos=1)
1654 self.assert_called('POST', '/servers/uuid2/action',
1655 {'evacuate': {'host': 'target_hyper',
1656 'onSharedStorage': True}}, pos=2)
1657 self.assert_called('POST', '/servers/uuid3/action',
1658 {'evacuate': {'host': 'target_hyper',
1659 'onSharedStorage': True}}, pos=3)
1660 self.assert_called('POST', '/servers/uuid4/action',
1661 {'evacuate': {'host': 'target_hyper',
1662 'onSharedStorage': True}}, pos=4)
1663
1664 def test_host_evacuate_with_no_target_host(self):
1665 self.run_command('host-evacuate --on-shared-storage hyper')
1666 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1667 self.assert_called('POST', '/servers/uuid1/action',
1668 {'evacuate': {'onSharedStorage': True}}, pos=1)
1669 self.assert_called('POST', '/servers/uuid2/action',
1670 {'evacuate': {'onSharedStorage': True}}, pos=2)
1671 self.assert_called('POST', '/servers/uuid3/action',
1672 {'evacuate': {'onSharedStorage': True}}, pos=3)
1673 self.assert_called('POST', '/servers/uuid4/action',
1674 {'evacuate': {'onSharedStorage': True}}, pos=4)
1675
1676 def test_host_servers_migrate(self):
1677 self.run_command('host-servers-migrate hyper')
1678 self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
1679 self.assert_called('POST',
1680 '/servers/uuid1/action', {'migrate': None}, pos=1)
1681 self.assert_called('POST',
1682 '/servers/uuid2/action', {'migrate': None}, pos=2)
1683 self.assert_called('POST',
1684 '/servers/uuid3/action', {'migrate': None}, pos=3)
1685 self.assert_called('POST',
1686 '/servers/uuid4/action', {'migrate': None}, pos=4)
1687
1688 def test_hypervisor_list(self):
1689 self.run_command('hypervisor-list')
1690 self.assert_called('GET', '/os-hypervisors')
1691
1692 def test_hypervisor_list_matching(self):
1693 self.run_command('hypervisor-list --matching hyper')
1694 self.assert_called('GET', '/os-hypervisors/hyper/search')
1695
1696 def test_hypervisor_servers(self):
1697 self.run_command('hypervisor-servers hyper')
1698 self.assert_called('GET', '/os-hypervisors/hyper/servers')
1699
1700 def test_hypervisor_show_by_id(self):
1701 self.run_command('hypervisor-show 1234')
1702 self.assert_called('GET', '/os-hypervisors/1234')
1703
1704 def test_hypervisor_show_by_name(self):
1705 self.run_command('hypervisor-show hyper1')
1706 self.assert_called('GET', '/os-hypervisors/detail')
1707
1708 def test_hypervisor_uptime_by_id(self):
1709 self.run_command('hypervisor-uptime 1234')
1710 self.assert_called('GET', '/os-hypervisors/1234/uptime')
1711
1712 def test_hypervisor_uptime_by_name(self):
1713 self.run_command('hypervisor-uptime hyper1')
1714 self.assert_called('GET', '/os-hypervisors/1234/uptime')
1715
1716 def test_hypervisor_stats(self):
1717 self.run_command('hypervisor-stats')
1718 self.assert_called('GET', '/os-hypervisors/statistics')
1719
1720 def test_quota_show(self):
1721 self.run_command(
1722 'quota-show --tenant '
1723 '97f4c221bff44578b0300df4ef119353')
1724 self.assert_called(
1725 'GET',
1726 '/os-quota-sets/97f4c221bff44578b0300df4ef119353')
1727
1728 def test_user_quota_show(self):
1729 self.run_command(
1730 'quota-show --tenant '
1731 '97f4c221bff44578b0300df4ef119353 --user u1')
1732 self.assert_called(
1733 'GET',
1734 '/os-quota-sets/97f4c221bff44578b0300df4ef119353?user_id=u1')
1735
1736 def test_quota_show_no_tenant(self):
1737 self.run_command('quota-show')
1738 self.assert_called('GET', '/os-quota-sets/tenant_id')
1739
1740 def test_quota_defaults(self):
1741 self.run_command(
1742 'quota-defaults --tenant '
1743 '97f4c221bff44578b0300df4ef119353')
1744 self.assert_called(
1745 'GET',
1746 '/os-quota-sets/97f4c221bff44578b0300df4ef119353/defaults')
1747
1748 def test_quota_defaults_no_tenant(self):
1749 self.run_command('quota-defaults')
1750 self.assert_called('GET', '/os-quota-sets/tenant_id/defaults')
1751
1752 def test_quota_update(self):
1753 self.run_command(
1754 'quota-update 97f4c221bff44578b0300df4ef119353'
1755 ' --instances=5')
1756 self.assert_called(
1757 'PUT',
1758 '/os-quota-sets/97f4c221bff44578b0300df4ef119353',
1759 {'quota_set': {'instances': 5,
1760 'tenant_id': '97f4c221bff44578b0300df4ef119353'}})
1761
1762 def test_user_quota_update(self):
1763 self.run_command(
1764 'quota-update 97f4c221bff44578b0300df4ef119353'
1765 ' --user=u1'
1766 ' --instances=5')
1767 self.assert_called(
1768 'PUT',
1769 '/os-quota-sets/97f4c221bff44578b0300df4ef119353?user_id=u1',
1770 {'quota_set': {'instances': 5,
1771 'tenant_id': '97f4c221bff44578b0300df4ef119353'}})
1772
1773 def test_quota_force_update(self):
1774 self.run_command(
1775 'quota-update 97f4c221bff44578b0300df4ef119353'
1776 ' --instances=5 --force')
1777 self.assert_called(
1778 'PUT', '/os-quota-sets/97f4c221bff44578b0300df4ef119353',
1779 {'quota_set': {'force': True,
1780 'instances': 5,
1781 'tenant_id': '97f4c221bff44578b0300df4ef119353'}})
1782
1783 def test_quota_update_fixed_ip(self):
1784 self.run_command(
1785 'quota-update 97f4c221bff44578b0300df4ef119353'
1786 ' --fixed-ips=5')
1787 self.assert_called(
1788 'PUT', '/os-quota-sets/97f4c221bff44578b0300df4ef119353',
1789 {'quota_set': {'fixed_ips': 5,
1790 'tenant_id': '97f4c221bff44578b0300df4ef119353'}})
1791
1792 def test_quota_delete(self):
1793 self.run_command('quota-delete --tenant '
1794 '97f4c221bff44578b0300df4ef119353')
1795 self.assert_called('DELETE',
1796 '/os-quota-sets/97f4c221bff44578b0300df4ef119353')
1797
1798 def test_user_quota_delete(self):
1799 self.run_command('quota-delete --tenant '
1800 '97f4c221bff44578b0300df4ef119353 '
1801 '--user u1')
1802 self.assert_called(
1803 'DELETE',
1804 '/os-quota-sets/97f4c221bff44578b0300df4ef119353?user_id=u1')
1805
1806 def test_quota_class_show(self):
1807 self.run_command('quota-class-show test')
1808 self.assert_called('GET', '/os-quota-class-sets/test')
1809
1810 def test_quota_class_update(self):
1811 # The list of args we can update.
1812 args = (
1813 '--instances', '--cores', '--ram', '--floating-ips', '--fixed-ips',
1814 '--metadata-items', '--injected-files',
1815 '--injected-file-content-bytes', '--injected-file-path-bytes',
1816 '--key-pairs', '--security-groups', '--security-group-rules',
1817 '--server-groups', '--server-group-members'
1818 )
1819 for arg in args:
1820 self.run_command('quota-class-update '
1821 '97f4c221bff44578b0300df4ef119353 '
1822 '%s=5' % arg)
1823 request_param = arg[2:].replace('-', '_')
1824 body = {'quota_class_set': {request_param: 5}}
1825 self.assert_called(
1826 'PUT', '/os-quota-class-sets/97f4c221bff44578b0300df4ef119353',
1827 body)
1828
1829 def test_network_list(self):
1830 self.run_command('network-list')
1831 self.assert_called('GET', '/os-networks')
1832
1833 def test_network_list_fields(self):
1834 output = self.run_command(
1835 'network-list --fields '
1836 'vlan,project_id')
1837 self.assert_called('GET', '/os-networks')
1838 self.assertIn('1234', output)
1839 self.assertIn('4ffc664c198e435e9853f2538fbcd7a7', output)
1840
1841 def test_network_show(self):
1842 self.run_command('network-show 1')
1843 self.assert_called('GET', '/os-networks/1')
1844
1845 def test_cloudpipe_list(self):
1846 self.run_command('cloudpipe-list')
1847 self.assert_called('GET', '/os-cloudpipe')
1848
1849 def test_cloudpipe_create(self):
1850 self.run_command('cloudpipe-create myproject')
1851 body = {'cloudpipe': {'project_id': "myproject"}}
1852 self.assert_called('POST', '/os-cloudpipe', body)
1853
1854 def test_cloudpipe_configure(self):
1855 self.run_command('cloudpipe-configure 192.168.1.1 1234')
1856 body = {'configure_project': {'vpn_ip': "192.168.1.1",
1857 'vpn_port': '1234'}}
1858 self.assert_called('PUT', '/os-cloudpipe/configure-project', body)
1859
1860 def test_network_associate_host(self):
1861 self.run_command('network-associate-host 1 testHost')
1862 body = {'associate_host': 'testHost'}
1863 self.assert_called('POST', '/os-networks/1/action', body)
1864
1865 def test_network_associate_project(self):
1866 self.run_command('network-associate-project 1')
1867 body = {'id': "1"}
1868 self.assert_called('POST', '/os-networks/add', body)
1869
1870 def test_network_disassociate_host(self):
1871 self.run_command('network-disassociate --host-only 1 2')
1872 body = {'disassociate_host': None}
1873 self.assert_called('POST', '/os-networks/2/action', body)
1874
1875 def test_network_disassociate_project(self):
1876 self.run_command('network-disassociate --project-only 1 2')
1877 body = {'disassociate_project': None}
1878 self.assert_called('POST', '/os-networks/2/action', body)
1879
1880 def test_network_create_v4(self):
1881 self.run_command('network-create --fixed-range-v4 10.0.1.0/24'
1882 ' --dns1 10.0.1.254 new_network')
1883 body = {'network': {'cidr': '10.0.1.0/24', 'label': 'new_network',
1884 'dns1': '10.0.1.254'}}
1885 self.assert_called('POST', '/os-networks', body)
1886
1887 def test_network_create_v6(self):
1888 self.run_command('network-create --fixed-range-v6 2001::/64'
1889 ' new_network')
1890 body = {'network': {'cidr_v6': '2001::/64', 'label': 'new_network'}}
1891 self.assert_called('POST', '/os-networks', body)
1892
1893 def test_network_create_invalid(self):
1894 cmd = 'network-create 10.0.1.0'
1895 self.assertRaises(exceptions.CommandError, self.run_command, cmd)
1896
1897 def test_network_create_multi_host(self):
1898 self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
1899 ' --multi-host=T new_network')
1900 body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
1901 'multi_host': True}}
1902 self.assert_called('POST', '/os-networks', body)
1903
1904 self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
1905 ' --multi-host=True new_network')
1906 body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
1907 'multi_host': True}}
1908 self.assert_called('POST', '/os-networks', body)
1909
1910 self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
1911 ' --multi-host=1 new_network')
1912 body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
1913 'multi_host': True}}
1914 self.assert_called('POST', '/os-networks', body)
1915
1916 self.run_command('network-create --fixed-range-v4 192.168.1.0/24'
1917 ' --multi-host=F new_network')
1918 body = {'network': {'cidr': '192.168.1.0/24', 'label': 'new_network',
1919 'multi_host': False}}
1920 self.assert_called('POST', '/os-networks', body)
1921
1922 def test_network_create_vlan(self):
1923 self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
1924 ' --vlan=200 new_network')
1925 body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
1926 'vlan': 200}}
1927 self.assert_called('POST', '/os-networks', body)
1928
1929 def test_network_create_vlan_start(self):
1930 self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
1931 ' --vlan-start=100 new_network')
1932 body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
1933 'vlan_start': 100}}
1934 self.assert_called('POST', '/os-networks', body)
1935
1936 def test_network_create_extra_args(self):
1937 self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
1938 ' --enable-dhcp F --dhcp-server 192.168.0.2'
1939 ' --share-address T --allowed-start 192.168.0.10'
1940 ' --allowed-end 192.168.0.20 --mtu 9000 new_network')
1941 body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
1942 'enable_dhcp': False, 'dhcp_server': '192.168.0.2',
1943 'share_address': True, 'mtu': 9000,
1944 'allowed_start': '192.168.0.10',
1945 'allowed_end': '192.168.0.20'}}
1946 self.assert_called('POST', '/os-networks', body)
1947
1948 def test_network_delete(self):
1949 self.run_command('network-delete 1')
1950 self.assert_called('DELETE', '/os-networks/1')
1951
1952 def test_add_fixed_ip(self):
1953 self.run_command('add-fixed-ip sample-server 1')
1954 self.assert_called('POST', '/servers/1234/action',
1955 {'addFixedIp': {'networkId': '1'}})
1956
1957 def test_remove_fixed_ip(self):
1958 self.run_command('remove-fixed-ip sample-server 10.0.0.10')
1959 self.assert_called('POST', '/servers/1234/action',
1960 {'removeFixedIp': {'address': '10.0.0.10'}})
1961
1962 def test_backup(self):
1963 self.run_command('backup sample-server back1 daily 1')
1964 self.assert_called('POST', '/servers/1234/action',
1965 {'createBackup': {'name': 'back1',
1966 'backup_type': 'daily',
1967 'rotation': '1'}})
1968 self.run_command('backup 1234 back1 daily 1')
1969 self.assert_called('POST', '/servers/1234/action',
1970 {'createBackup': {'name': 'back1',
1971 'backup_type': 'daily',
1972 'rotation': '1'}})
1973
1974 def test_absolute_limits(self):
1975 self.run_command('absolute-limits')
1976 self.assert_called('GET', '/limits')
1977
1978 self.run_command('absolute-limits --reserved')
1979 self.assert_called('GET', '/limits?reserved=1')
1980
1981 self.run_command('absolute-limits --tenant 1234')
1982 self.assert_called('GET', '/limits?tenant_id=1234')
1983
1984 def test_evacuate(self):
1985 self.run_command('evacuate sample-server new_host')
1986 self.assert_called('POST', '/servers/1234/action',
1987 {'evacuate': {'host': 'new_host',
1988 'onSharedStorage': False}})
1989 self.run_command('evacuate sample-server new_host '
1990 '--password NewAdminPass')
1991 self.assert_called('POST', '/servers/1234/action',
1992 {'evacuate': {'host': 'new_host',
1993 'onSharedStorage': False,
1994 'adminPass': 'NewAdminPass'}})
1995 self.run_command('evacuate sample-server new_host '
1996 '--on-shared-storage')
1997 self.assert_called('POST', '/servers/1234/action',
1998 {'evacuate': {'host': 'new_host',
1999 'onSharedStorage': True}})
2000
2001 def test_evacuate_with_no_target_host(self):
2002 self.run_command('evacuate sample-server')
2003 self.assert_called('POST', '/servers/1234/action',
2004 {'evacuate': {'onSharedStorage': False}})
2005 self.run_command('evacuate sample-server --password NewAdminPass')
2006 self.assert_called('POST', '/servers/1234/action',
2007 {'evacuate': {'onSharedStorage': False,
2008 'adminPass': 'NewAdminPass'}})
2009 self.run_command('evacuate sample-server --on-shared-storage')
2010 self.assert_called('POST', '/servers/1234/action',
2011 {'evacuate': {'onSharedStorage': True}})
2012
2013 def test_get_password(self):
2014 self.run_command('get-password sample-server /foo/id_rsa')
2015 self.assert_called('GET', '/servers/1234/os-server-password')
2016
2017 def test_get_password_without_key(self):
2018 self.run_command('get-password sample-server')
2019 self.assert_called('GET', '/servers/1234/os-server-password')
2020
2021 def test_clear_password(self):
2022 self.run_command('clear-password sample-server')
2023 self.assert_called('DELETE', '/servers/1234/os-server-password')
2024
2025 def test_availability_zone_list(self):
2026 self.run_command('availability-zone-list')
2027 self.assert_called('GET', '/os-availability-zone/detail')
2028
2029 def test_security_group_create(self):
2030 self.run_command('secgroup-create test FAKE_SECURITY_GROUP')
2031 self.assert_called('POST', '/os-security-groups',
2032 {'security_group':
2033 {'name': 'test',
2034 'description': 'FAKE_SECURITY_GROUP'}})
2035
2036 def test_security_group_update(self):
2037 self.run_command('secgroup-update test te FAKE_SECURITY_GROUP')
2038 self.assert_called('PUT', '/os-security-groups/1',
2039 {'security_group':
2040 {'name': 'te',
2041 'description': 'FAKE_SECURITY_GROUP'}})
2042
2043 def test_security_group_list(self):
2044 self.run_command('secgroup-list')
2045 self.assert_called('GET', '/os-security-groups')
2046
2047 def test_security_group_add_rule(self):
2048 self.run_command('secgroup-add-rule test tcp 22 22 10.0.0.0/8')
2049 self.assert_called('POST', '/os-security-group-rules',
2050 {'security_group_rule':
2051 {'from_port': 22,
2052 'ip_protocol': 'tcp',
2053 'to_port': 22,
2054 'parent_group_id': 1,
2055 'cidr': '10.0.0.0/8',
2056 'group_id': None}})
2057
2058 def test_security_group_delete_rule(self):
2059 self.run_command('secgroup-delete-rule test TCP 22 22 10.0.0.0/8')
2060 self.assert_called('DELETE', '/os-security-group-rules/11')
2061
2062 def test_security_group_delete_rule_protocol_case(self):
2063 self.run_command('secgroup-delete-rule test tcp 22 22 10.0.0.0/8')
2064 self.assert_called('DELETE', '/os-security-group-rules/11')
2065
2066 def test_security_group_add_group_rule(self):
2067 self.run_command('secgroup-add-group-rule test test2 tcp 22 22')
2068 self.assert_called('POST', '/os-security-group-rules',
2069 {'security_group_rule':
2070 {'from_port': 22,
2071 'ip_protocol': 'TCP',
2072 'to_port': 22,
2073 'parent_group_id': 1,
2074 'cidr': None,
2075 'group_id': 2}})
2076
2077 def test_security_group_delete_valid_group_rule(self):
2078 self.run_command('secgroup-delete-group-rule test test2 TCP 222 222')
2079 self.assert_called('DELETE', '/os-security-group-rules/12')
2080
2081 def test_security_group_delete_valid_group_rule_protocol_case(self):
2082 self.run_command('secgroup-delete-group-rule test test2 tcp 222 222')
2083 self.assert_called('DELETE', '/os-security-group-rules/12')
2084
2085 def test_security_group_delete_invalid_group_rule(self):
2086 self.run_command('secgroup-delete-group-rule test test4 TCP -1 -1')
2087 self.assert_called('DELETE', '/os-security-group-rules/14')
2088
2089 def test_security_group_delete_invalid_group_rule_protocol_case(self):
2090 self.run_command('secgroup-delete-group-rule test test4 tcp -1 -1')
2091 self.assert_called('DELETE', '/os-security-group-rules/14')
2092
2093 def test_security_group_list_rules(self):
2094 self.run_command('secgroup-list-rules test')
2095 self.assert_called('GET', '/os-security-groups')
2096
2097 def test_security_group_list_all_tenants(self):
2098 self.run_command('secgroup-list --all-tenants 1')
2099 self.assert_called('GET', '/os-security-groups?all_tenants=1')
2100
2101 def test_security_group_delete(self):
2102 self.run_command('secgroup-delete test')
2103 self.assert_called('DELETE', '/os-security-groups/1')
2104
2105 def test_server_security_group_add(self):
2106 self.run_command('add-secgroup sample-server testgroup')
2107 self.assert_called('POST', '/servers/1234/action',
2108 {'addSecurityGroup': {'name': 'testgroup'}})
2109
2110 def test_server_security_group_remove(self):
2111 self.run_command('remove-secgroup sample-server testgroup')
2112 self.assert_called('POST', '/servers/1234/action',
2113 {'removeSecurityGroup': {'name': 'testgroup'}})
2114
2115 def test_server_security_group_list(self):
2116 self.run_command('list-secgroup 1234')
2117 self.assert_called('GET', '/servers/1234/os-security-groups')
2118
2119 def test_interface_list(self):
2120 self.run_command('interface-list 1234')
2121 self.assert_called('GET', '/servers/1234/os-interface')
2122
2123 def test_interface_attach(self):
2124 self.run_command('interface-attach --port-id port_id 1234')
2125 self.assert_called('POST', '/servers/1234/os-interface',
2126 {'interfaceAttachment': {'port_id': 'port_id'}})
2127
2128 def test_interface_detach(self):
2129 self.run_command('interface-detach 1234 port_id')
2130 self.assert_called('DELETE', '/servers/1234/os-interface/port_id')
2131
2132 def test_volume_list(self):
2133 self.run_command('volume-list')
2134 self.assert_called('GET', '/volumes/detail')
2135
2136 def test_volume_show(self):
2137 self.run_command('volume-show Work')
2138 self.assert_called('GET', '/volumes?name=Work', pos=-2)
2139 self.assert_called(
2140 'GET',
2141 '/volumes/15e59938-07d5-11e1-90e3-e3dffe0c5983',
2142 pos=-1
2143 )
2144
2145 def test_volume_create(self):
2146 self.run_command('volume-create 2 --display-name Work')
2147 self.assert_called('POST', '/volumes',
2148 {'volume':
2149 {'display_name': 'Work',
2150 'imageRef': None,
2151 'availability_zone': None,
2152 'volume_type': None,
2153 'display_description': None,
2154 'snapshot_id': None,
2155 'size': 2}})
2156
2157 def test_volume_delete(self):
2158 self.run_command('volume-delete Work')
2159 self.assert_called('DELETE',
2160 '/volumes/15e59938-07d5-11e1-90e3-e3dffe0c5983')
2161
2162 def test_volume_delete_multiple(self):
2163 self.run_command('volume-delete Work Work2')
2164 self.assert_called('DELETE',
2165 '/volumes/15e59938-07d5-11e1-90e3-e3dffe0c5983',
2166 pos=-5)
2167 self.assert_called('DELETE',
2168 '/volumes/15e59938-07d5-11e1-90e3-ee32ba30feaa',
2169 pos=-1)
2170
2171 def test_volume_attach(self):
2172 self.run_command('volume-attach sample-server Work /dev/vdb')
2173 self.assert_called('POST', '/servers/1234/os-volume_attachments',
2174 {'volumeAttachment':
2175 {'device': '/dev/vdb',
2176 'volumeId': 'Work'}})
2177
2178 def test_volume_attach_without_device(self):
2179 self.run_command('volume-attach sample-server Work')
2180 self.assert_called('POST', '/servers/1234/os-volume_attachments',
2181 {'volumeAttachment':
2182 {'device': None,
2183 'volumeId': 'Work'}})
2184
2185 def test_volume_update(self):
2186 self.run_command('volume-update sample-server Work Work')
2187 self.assert_called('PUT', '/servers/1234/os-volume_attachments/Work',
2188 {'volumeAttachment': {'volumeId': 'Work'}})
2189
2190 def test_volume_detach(self):
2191 self.run_command('volume-detach sample-server Work')
2192 self.assert_called('DELETE',
2193 '/servers/1234/os-volume_attachments/Work')
2194
2195 def test_instance_action_list(self):
2196 self.run_command('instance-action-list sample-server')
2197 self.assert_called('GET', '/servers/1234/os-instance-actions')
2198
2199 def test_instance_action_get(self):
2200 self.run_command('instance-action sample-server req-abcde12345')
2201 self.assert_called(
2202 'GET',
2203 '/servers/1234/os-instance-actions/req-abcde12345')
2204
2205 def test_cell_show(self):
2206 self.run_command('cell-show child_cell')
2207 self.assert_called('GET', '/os-cells/child_cell')
2208
2209 def test_cell_capacities_with_cell_name(self):
2210 self.run_command('cell-capacities --cell child_cell')
2211 self.assert_called('GET', '/os-cells/child_cell/capacities')
2212
2213 def test_cell_capacities_without_cell_name(self):
2214 self.run_command('cell-capacities')
2215 self.assert_called('GET', '/os-cells/capacities')
2216
2217 def test_migration_list(self):
2218 self.run_command('migration-list')
2219 self.assert_called('GET', '/os-migrations')
2220
2221 def test_migration_list_with_filters(self):
2222 self.run_command('migration-list --host host1 --cell_name child1 '
2223 '--status finished')
2224 self.assert_called('GET',
2225 '/os-migrations?cell_name=child1&host=host1'
2226 '&status=finished')
2227
2228 @mock.patch('novaclient.v2.shell._find_server')
2229 @mock.patch('os.system')
2230 def test_ssh(self, mock_system, mock_find_server):
2231 class FakeResources(object):
2232 addresses = {
2233 "skynet": [
2234 {'version': 4, 'addr': "1.1.1.1",
2235 "OS-EXT-IPS:type": 'fixed'},
2236 {'version': 4, 'addr': "2.2.2.2",
2237 "OS-EXT-IPS:type": 'floating'},
2238 {'version': 6, 'addr': "2607:f0d0:1002::4",
2239 "OS-EXT-IPS:type": 'fixed'},
2240 {'version': 6, 'addr': "7612:a1b2:2004::6"}
2241 ]
2242 }
2243 mock_find_server.return_value = FakeResources()
2244
2245 self.run_command("ssh --login bob server")
2246 mock_system.assert_called_with("ssh -4 -p22 bob@2.2.2.2 ")
2247 self.run_command("ssh alice@server")
2248 mock_system.assert_called_with("ssh -4 -p22 alice@2.2.2.2 ")
2249 self.run_command("ssh --port 202 server")
2250 mock_system.assert_called_with("ssh -4 -p202 root@2.2.2.2 ")
2251 self.run_command("ssh --private server")
2252 mock_system.assert_called_with("ssh -4 -p22 root@1.1.1.1 ")
2253 self.run_command("ssh -i ~/my_rsa_key server --private")
2254 mock_system.assert_called_with("ssh -4 -p22 -i ~/my_rsa_key "
2255 "root@1.1.1.1 ")
2256 self.run_command("ssh --extra-opts -1 server")
2257 mock_system.assert_called_with("ssh -4 -p22 root@2.2.2.2 -1")
2258
2259 self.run_command("ssh --ipv6 --login carol server")
2260 mock_system.assert_called_with("ssh -6 -p22 carol@7612:a1b2:2004::6 ")
2261 self.run_command("ssh --ipv6 dan@server")
2262 mock_system.assert_called_with("ssh -6 -p22 dan@7612:a1b2:2004::6 ")
2263 self.run_command("ssh --ipv6 --port 2022 server")
2264 mock_system.assert_called_with("ssh -6 -p2022 "
2265 "root@7612:a1b2:2004::6 ")
2266 self.run_command("ssh --ipv6 --private server")
2267 mock_system.assert_called_with("ssh -6 -p22 root@2607:f0d0:1002::4 ")
2268 self.run_command("ssh --ipv6 --identity /home/me/my_dsa_key "
2269 "--private server")
2270 mock_system.assert_called_with("ssh -6 -p22 -i /home/me/my_dsa_key "
2271 "root@2607:f0d0:1002::4 ")
2272 self.run_command("ssh --ipv6 --private --extra-opts -1 server")
2273 mock_system.assert_called_with("ssh -6 -p22 "
2274 "root@2607:f0d0:1002::4 -1")
2275
2276 @mock.patch('novaclient.v2.shell._find_server')
2277 @mock.patch('os.system')
2278 def test_ssh_multinet(self, mock_system, mock_find_server):
2279 class FakeResources(object):
2280 addresses = {
2281 "skynet": [
2282 {'version': 4, 'addr': "1.1.1.1",
2283 "OS-EXT-IPS:type": 'fixed'},
2284 {'version': 4, 'addr': "2.2.2.2"},
2285 {'version': 6, 'addr': "2607:f0d0:1002::4",
2286 "OS-EXT-IPS:type": 'fixed'}
2287 ],
2288 "other": [
2289 {'version': 4, 'addr': "2.3.4.5"},
2290 {'version': 6, 'addr': "7612:a1b2:2004::6"}
2291 ]
2292 }
2293 mock_find_server.return_value = FakeResources()
2294
2295 self.run_command("ssh --network other server")
2296 mock_system.assert_called_with("ssh -4 -p22 root@2.3.4.5 ")
2297 self.run_command("ssh --ipv6 --network other server")
2298 mock_system.assert_called_with("ssh -6 -p22 root@7612:a1b2:2004::6 ")
2299 self.assertRaises(exceptions.ResourceNotFound,
2300 self.run_command,
2301 "ssh --ipv6 --network nonexistent server")
2302
2303 def test_keypair_add(self):
2304 self.run_command('keypair-add test')
2305 self.assert_called('POST', '/os-keypairs',
2306 {'keypair':
2307 {'name': 'test'}})
2308
2309 @mock.patch.object(builtins, 'open',
2310 mock.mock_open(read_data='FAKE_PUBLIC_KEY'))
2311 def test_keypair_import(self):
2312 self.run_command('keypair-add --pub-key test.pub test')
2313 self.assert_called(
2314 'POST', '/os-keypairs', {
2315 'keypair': {'public_key': 'FAKE_PUBLIC_KEY', 'name': 'test'}})
2316
2317 def test_keypair_list(self):
2318 self.run_command('keypair-list')
2319 self.assert_called('GET', '/os-keypairs')
2320
2321 def test_keypair_show(self):
2322 self.run_command('keypair-show test')
2323 self.assert_called('GET', '/os-keypairs/test')
2324
2325 def test_keypair_delete(self):
2326 self.run_command('keypair-delete test')
2327 self.assert_called('DELETE', '/os-keypairs/test')
2328
2329 def test_create_server_group(self):
2330 self.run_command('server-group-create wjsg affinity')
2331 self.assert_called('POST', '/os-server-groups',
2332 {'server_group': {'name': 'wjsg',
2333 'policies': ['affinity']}})
2334
2335 def test_delete_multi_server_groups(self):
2336 self.run_command('server-group-delete 12345 56789')
2337 self.assert_called('DELETE', '/os-server-groups/56789')
2338 self.assert_called('DELETE', '/os-server-groups/12345', pos=-2)
2339
2340
2341class ShellTestV11(ShellTest):
2342 FAKE_ENV = {
2343 'NOVA_USERNAME': 'username',
2344 'NOVA_PASSWORD': 'password',
2345 'NOVA_PROJECT_ID': 'project_id',
2346 'OS_COMPUTE_API_VERSION': '1.1',
2347 'NOVA_URL': 'http://no.where',
2348 'OS_AUTH_URL': 'http://no.where/v2.0',
2349 }
2350
2351
2352class ShellTestV3(ShellTest):
2353 FAKE_ENV = {
2354 'NOVA_USERNAME': 'username',
2355 'NOVA_PASSWORD': 'password',
2356 'NOVA_PROJECT_ID': 'project_id',
2357 'OS_COMPUTE_API_VERSION': '3',
2358 'NOVA_URL': 'http://no.where',
2359 'OS_AUTH_URL': 'http://no.where/v2.0',
2360 }
2361
2362
2363class ShellWithSessionClientTest(ShellTest):
2364
2365 def setUp(self):
2366 """Run before each test."""
2367 super(ShellWithSessionClientTest, self).setUp()
2368 self.useFixture(fixtures.MonkeyPatch(
2369 'novaclient.client.get_client_class',
2370 lambda *_: fakes.FakeSessionClient))
2371
2372
2373class GetSecgroupTest(utils.TestCase):
2374 def test_with_integer(self):
2375 cs = mock.Mock(**{
2376 'security_groups.get.return_value': 'sec_group',
2377 'security_groups.list.return_value': [],
2378 })
2379 result = novaclient.v2.shell._get_secgroup(cs, '1')
2380 self.assertEqual('sec_group', result)
2381 cs.security_groups.get.assert_called_once_with('1')
2382
2383 def test_with_uuid(self):
2384 cs = mock.Mock(**{
2385 'security_groups.get.return_value': 'sec_group',
2386 'security_groups.list.return_value': [],
2387 })
2388 result = novaclient.v2.shell._get_secgroup(
2389 cs, 'c0c32459-dc5f-44dc-9a0a-473b28bac831')
2390 self.assertEqual('sec_group', result)
2391 cs.security_groups.get.assert_called_once_with(
2392 'c0c32459-dc5f-44dc-9a0a-473b28bac831')
2393
2394 def test_with_an_nonexisting_name(self):
2395 cs = mock.Mock(**{
2396 'security_groups.get.return_value': 'sec_group',
2397 'security_groups.list.return_value': [],
2398 })
2399 self.assertRaises(exceptions.CommandError,
2400 novaclient.v2.shell._get_secgroup,
2401 cs,
2402 'abc')
2403
2404 def test_with_non_unique_name(self):
2405 group_one = mock.MagicMock()
2406 group_one.name = 'group_one'
2407 cs = mock.Mock(**{
2408 'security_groups.get.return_value': 'sec_group',
2409 'security_groups.list.return_value': [group_one, group_one],
2410 })
2411 self.assertRaises(exceptions.NoUniqueMatch,
2412 novaclient.v2.shell._get_secgroup,
2413 cs,
2414 'group_one')
2415
2416
2417class GetFirstEndpointTest(utils.TestCase):
2418 def test_only_one_endpoint(self):
2419 """If there is only one endpoint, it is returned."""
2420 endpoint = {"url": "test"}
2421 result = novaclient.v2.shell._get_first_endpoint([endpoint], "XYZ")
2422 self.assertEqual(endpoint, result)
2423
2424 def test_multiple_endpoints(self):
2425 """If there are multiple endpoints, the first one of the appropriate
2426 region is returned.
2427
2428 """
2429 endpoints = [
2430 {"region": "XYZ"},
2431 {"region": "ORD", "number": 1},
2432 {"region": "ORD", "number": 2}
2433 ]
2434 result = novaclient.v2.shell._get_first_endpoint(endpoints, "ORD")
2435 self.assertEqual(endpoints[1], result)
2436
2437 def test_multiple_endpoints_but_none_suitable(self):
2438 """If there are multiple endpoints but none of them are suitable, an
2439 exception is raised.
2440
2441 """
2442 endpoints = [
2443 {"region": "XYZ"},
2444 {"region": "PQR"},
2445 {"region": "STU"}
2446 ]
2447 self.assertRaises(LookupError,
2448 novaclient.v2.shell._get_first_endpoint,
2449 endpoints, "ORD")
2450
2451 def test_no_endpoints(self):
2452 """If there are no endpoints available, an exception is raised."""
2453 self.assertRaises(LookupError,
2454 novaclient.v2.shell._get_first_endpoint,
2455 [], "ORD")