python-novaclient/tests/v1_1/test_shell.py

535 lines
21 KiB
Python

# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import os
import mock
import sys
import tempfile
import novaclient.shell
import novaclient.client
from novaclient import exceptions
from novaclient.openstack.common import timeutils
from tests.v1_1 import fakes
from tests import utils
class ShellTest(utils.TestCase):
# Patch os.environ to avoid required auth info.
def setUp(self):
"""Run before each test."""
self.old_environment = os.environ.copy()
os.environ = {
'NOVA_USERNAME': 'username',
'NOVA_PASSWORD': 'password',
'NOVA_PROJECT_ID': 'project_id',
'OS_COMPUTE_API_VERSION': '1.1',
'NOVA_URL': 'http://no.where',
}
self.shell = novaclient.shell.OpenStackComputeShell()
#HACK(bcwaldon): replace this when we start using stubs
self.old_get_client_class = novaclient.client.get_client_class
novaclient.client.get_client_class = lambda *_: fakes.FakeClient
def tearDown(self):
os.environ = self.old_environment
# For some method like test_image_meta_bad_action we are
# testing a SystemExit to be thrown and object self.shell has
# no time to get instantatiated which is OK in this case, so
# we make sure the method is there before launching it.
if hasattr(self.shell, 'cs'):
self.shell.cs.clear_callstack()
#HACK(bcwaldon): replace this when we start using stubs
novaclient.client.get_client_class = self.old_get_client_class
timeutils.clear_time_override()
def run_command(self, cmd):
self.shell.main(cmd.split())
def assert_called(self, method, url, body=None, **kwargs):
return self.shell.cs.assert_called(method, url, body, **kwargs)
def assert_called_anytime(self, method, url, body=None):
return self.shell.cs.assert_called_anytime(method, url, body)
def test_boot(self):
self.run_command('boot --flavor 1 --image 1 some-server')
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
'imageRef': '1',
'min_count': 1,
'max_count': 1,
}},
)
def test_boot_metadata(self):
self.run_command('boot --image 1 --flavor 1 --meta foo=bar=pants'
' --meta spam=eggs some-server ')
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
'imageRef': '1',
'metadata': {'foo': 'bar=pants', 'spam': 'eggs'},
'min_count': 1,
'max_count': 1,
}},
)
def test_boot_hints(self):
self.run_command('boot --image 1 --flavor 1 --hint a=b=c some-server ')
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'some-server',
'imageRef': '1',
'min_count': 1,
'max_count': 1,
},
'os:scheduler_hints': {'a': 'b=c'},
},
)
def test_boot_nics(self):
cmd = ('boot --image 1 --flavor 1 '
'--nic net-id=a=c,v4-fixed-ip=10.0.0.1 some-server')
self.run_command(cmd)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'some-server',
'imageRef': '1',
'min_count': 1,
'max_count': 1,
'networks': [
{'uuid': 'a=c', 'fixed_ip': '10.0.0.1'},
],
},
},
)
def test_boot_files(self):
testfile = os.path.join(os.path.dirname(__file__), 'testfile.txt')
expected_file_data = open(testfile).read().encode('base64')
cmd = 'boot some-server --flavor 1 --image 1 ' \
'--file /tmp/foo=%s --file /tmp/bar=%s'
self.run_command(cmd % (testfile, testfile))
self.assert_called_anytime(
'POST', '/servers',
{'server': {
'flavorRef': '1',
'name': 'some-server',
'imageRef': '1',
'min_count': 1,
'max_count': 1,
'personality': [
{'path': '/tmp/bar', 'contents': expected_file_data},
{'path': '/tmp/foo', 'contents': expected_file_data},
]},
},
)
def test_boot_invalid_file(self):
invalid_file = os.path.join(os.path.dirname(__file__),
'asdfasdfasdfasdf')
cmd = 'boot some-server --image 1 --file /foo=%s' % invalid_file
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
def test_flavor_list(self):
self.run_command('flavor-list')
self.assert_called_anytime('GET', '/flavors/detail')
def test_flavor_show(self):
self.run_command('flavor-show 1')
self.assert_called('GET', '/flavors/1')
def test_image_show(self):
self.run_command('image-show 1')
self.assert_called('GET', '/images/1')
def test_image_meta_set(self):
self.run_command('image-meta 1 set test_key=test_value')
self.assert_called('POST', '/images/1/metadata',
{'metadata': {'test_key': 'test_value'}})
def test_image_meta_del(self):
self.run_command('image-meta 1 delete test_key=test_value')
self.assert_called('DELETE', '/images/1/metadata/test_key')
def test_image_meta_bad_action(self):
tmp = tempfile.TemporaryFile()
# Suppress stdout and stderr
(stdout, stderr) = (sys.stdout, sys.stderr)
(sys.stdout, sys.stderr) = (tmp, tmp)
self.assertRaises(SystemExit, self.run_command,
'image-meta 1 BAD_ACTION test_key=test_value')
# Put stdout and stderr back
sys.stdout, sys.stderr = (stdout, stderr)
def test_image_list(self):
self.run_command('image-list')
self.assert_called('GET', '/images/detail')
def test_create_image(self):
self.run_command('image-create sample-server mysnapshot')
self.assert_called(
'POST', '/servers/1234/action',
{'createImage': {'name': 'mysnapshot', 'metadata': {}}},
)
def test_image_delete(self):
self.run_command('image-delete 1')
self.assert_called('DELETE', '/images/1')
def test_list(self):
self.run_command('list')
self.assert_called('GET', '/servers/detail')
def test_reboot(self):
self.run_command('reboot sample-server')
self.assert_called('POST', '/servers/1234/action',
{'reboot': {'type': 'SOFT'}})
self.run_command('reboot sample-server --hard')
self.assert_called('POST', '/servers/1234/action',
{'reboot': {'type': 'HARD'}})
def test_rebuild(self):
self.run_command('rebuild sample-server 1')
# XXX need a way to test multiple calls
#self.assert_called('POST', '/servers/1234/action',
# {'rebuild': {'imageRef': 1}})
self.assert_called('GET', '/images/2')
self.run_command('rebuild sample-server 1 --rebuild_password asdf')
# XXX need a way to test multiple calls
#self.assert_called('POST', '/servers/1234/action',
# {'rebuild': {'imageRef': 1, 'adminPass': 'asdf'}})
self.assert_called('GET', '/images/2')
def test_rename(self):
self.run_command('rename sample-server newname')
self.assert_called('PUT', '/servers/1234',
{'server': {'name': 'newname'}})
def test_resize(self):
self.run_command('resize sample-server 1')
self.assert_called('POST', '/servers/1234/action',
{'resize': {'flavorRef': 1}})
def test_resize_confirm(self):
self.run_command('resize-confirm sample-server')
self.assert_called('POST', '/servers/1234/action',
{'confirmResize': None})
def test_resize_revert(self):
self.run_command('resize-revert sample-server')
self.assert_called('POST', '/servers/1234/action',
{'revertResize': None})
@mock.patch('getpass.getpass', mock.Mock(return_value='p'))
def test_root_password(self):
self.run_command('root-password sample-server')
self.assert_called('POST', '/servers/1234/action',
{'changePassword': {'adminPass': 'p'}})
def test_show(self):
self.run_command('show 1234')
self.assert_called('GET', '/servers/1234', pos=-3)
self.assert_called('GET', '/flavors/1', pos=-2)
self.assert_called('GET', '/images/2')
def test_show_bad_id(self):
self.assertRaises(exceptions.CommandError,
self.run_command, 'show xxx')
def test_delete(self):
self.run_command('delete 1234')
self.assert_called('DELETE', '/servers/1234')
self.run_command('delete sample-server')
self.assert_called('DELETE', '/servers/1234')
def test_diagnostics(self):
self.run_command('diagnostics 1234')
self.assert_called('GET', '/servers/1234/diagnostics')
self.run_command('diagnostics sample-server')
self.assert_called('GET', '/servers/1234/diagnostics')
def test_actions(self):
self.run_command('actions 1234')
self.assert_called('GET', '/servers/1234/actions')
self.run_command('actions sample-server')
self.assert_called('GET', '/servers/1234/actions')
def test_set_meta_set(self):
self.run_command('meta 1234 set key1=val1 key2=val2')
self.assert_called('POST', '/servers/1234/metadata',
{'metadata': {'key1': 'val1', 'key2': 'val2'}})
def test_set_meta_delete_dict(self):
self.run_command('meta 1234 delete key1=val1 key2=val2')
self.assert_called('DELETE', '/servers/1234/metadata/key1')
self.assert_called('DELETE', '/servers/1234/metadata/key2', pos=-2)
def test_set_meta_delete_keys(self):
self.run_command('meta 1234 delete key1 key2')
self.assert_called('DELETE', '/servers/1234/metadata/key1')
self.assert_called('DELETE', '/servers/1234/metadata/key2', pos=-2)
def test_dns_create(self):
self.run_command('dns-create 192.168.1.1 testname testdomain')
self.assert_called('PUT',
'/os-floating-ip-dns/testdomain/entries/testname')
self.run_command('dns-create 192.168.1.1 testname testdomain --type A')
self.assert_called('PUT',
'/os-floating-ip-dns/testdomain/entries/testname')
def test_dns_create_public_domain(self):
self.run_command('dns-create-public-domain testdomain '
'--project test_project')
self.assert_called('PUT', '/os-floating-ip-dns/testdomain')
def test_dns_create_private_domain(self):
self.run_command('dns-create-private-domain testdomain '
'--availability_zone av_zone')
self.assert_called('PUT', '/os-floating-ip-dns/testdomain')
def test_dns_delete(self):
self.run_command('dns-delete testdomain testname')
self.assert_called('DELETE',
'/os-floating-ip-dns/testdomain/entries/testname')
def test_dns_delete_domain(self):
self.run_command('dns-delete-domain testdomain')
self.assert_called('DELETE', '/os-floating-ip-dns/testdomain')
def test_dns_list(self):
self.run_command('dns-list testdomain --ip 192.168.1.1')
self.assert_called('GET',
'/os-floating-ip-dns/testdomain/entries?ip=192.168.1.1')
self.run_command('dns-list testdomain --name testname')
self.assert_called('GET',
'/os-floating-ip-dns/testdomain/entries/testname')
def test_dns_domains(self):
self.run_command('dns-domains')
self.assert_called('GET', '/os-floating-ip-dns')
def test_usage_list(self):
self.run_command('usage-list --start 2000-01-20 --end 2005-02-01')
self.assert_called('GET',
'/os-simple-tenant-usage?' +
'start=2000-01-20T00:00:00&' +
'end=2005-02-01T00:00:00&' +
'detailed=1')
def test_usage_list_no_args(self):
timeutils.set_time_override(datetime.datetime(2005, 2, 1, 0, 0))
self.run_command('usage-list')
self.assert_called('GET',
'/os-simple-tenant-usage?' +
'start=2005-01-04T00:00:00&' +
'end=2005-02-02T00:00:00&' +
'detailed=1')
def test_flavor_delete(self):
self.run_command("flavor-delete flavordelete")
self.assert_called('DELETE', '/flavors/flavordelete')
def test_flavor_create(self):
self.run_command("flavor-create flavorcreate "
"1234 512 10 1 --swap 1024 --ephemeral 10")
body = {
"flavor": {
"name": "flavorcreate",
"ram": 512,
"vcpus": 1,
"disk": 10,
"OS-FLV-EXT-DATA:ephemeral": 10,
"id": 1234,
"swap": 1024,
"rxtx_factor": 1,
}
}
self.assert_called('POST', '/flavors', body, pos=-2)
self.assert_called('GET', '/flavors/1')
def test_aggregate_list(self):
self.run_command('aggregate-list')
self.assert_called('GET', '/os-aggregates')
def test_aggregate_create(self):
self.run_command('aggregate-create test_name nova1')
body = {"aggregate": {"name": "test_name",
"availability_zone": "nova1"}}
self.assert_called('POST', '/os-aggregates', body)
def test_aggregate_delete(self):
self.run_command('aggregate-delete 1')
self.assert_called('DELETE', '/os-aggregates/1')
def test_aggregate_update(self):
self.run_command('aggregate-update 1 new_name')
body = {"aggregate": {"name": "new_name"}}
self.assert_called('PUT', '/os-aggregates/1', body)
def test_aggregate_update_with_availability_zone(self):
self.run_command('aggregate-update 1 foo new_zone')
body = {"aggregate": {"name": "foo", "availability_zone": "new_zone"}}
self.assert_called('PUT', '/os-aggregates/1', body)
def test_aggregate_set_metadata(self):
self.run_command('aggregate-set-metadata 1 foo=bar delete_key')
body = {"set_metadata": {"metadata": {"foo": "bar",
"delete_key": None}}}
self.assert_called('POST', '/os-aggregates/1/action', body)
def test_aggregate_add_host(self):
self.run_command('aggregate-add-host 1 host1')
body = {"add_host": {"host": "host1"}}
self.assert_called('POST', '/os-aggregates/1/action', body)
def test_aggregate_remove_host(self):
self.run_command('aggregate-remove-host 1 host1')
body = {"remove_host": {"host": "host1"}}
self.assert_called('POST', '/os-aggregates/1/action', body)
def test_aggregate_details(self):
self.run_command('aggregate-details 1')
self.assert_called('GET', '/os-aggregates/1')
def test_live_migration(self):
self.run_command('live-migration sample-server hostname')
self.assert_called('POST', '/servers/1234/action',
{'os-migrateLive': {'host': 'hostname',
'block_migration': False,
'disk_over_commit': False}})
self.run_command('live-migration sample-server hostname \
--block_migrate')
self.assert_called('POST', '/servers/1234/action',
{'os-migrateLive': {'host': 'hostname',
'block_migration': True,
'disk_over_commit': False}})
self.run_command('live-migration sample-server hostname \
--block_migrate --disk_over_commit')
self.assert_called('POST', '/servers/1234/action',
{'os-migrateLive': {'host': 'hostname',
'block_migration': True,
'disk_over_commit': True}})
def test_reset_state(self):
self.run_command('reset-state sample-server')
self.assert_called('POST', '/servers/1234/action',
{'os-resetState': {'state': 'error'}})
self.run_command('reset-state sample-server --active')
self.assert_called('POST', '/servers/1234/action',
{'os-resetState': {'state': 'active'}})
def test_host_update_status(self):
self.run_command('host-update sample-host_1 --status enabled')
body = {'status': 'enabled'}
self.assert_called('PUT', '/os-hosts/sample-host_1', body)
def test_host_update_maintenance(self):
self.run_command('host-update sample-host_2 --maintenance enable')
body = {'maintenance_mode': 'enable'}
self.assert_called('PUT', '/os-hosts/sample-host_2', body)
def test_host_update_multiple_settings(self):
self.run_command('host-update sample-host_3 '
'--status disabled --maintenance enable')
body = {'status': 'disabled', 'maintenance_mode': 'enable'}
self.assert_called('PUT', '/os-hosts/sample-host_3', body)
def test_host_startup(self):
self.run_command('host-action sample-host --action startup')
self.assert_called('GET', '/os-hosts/sample-host/startup')
def test_host_shutdown(self):
self.run_command('host-action sample-host --action shutdown')
self.assert_called('GET', '/os-hosts/sample-host/shutdown')
def test_host_reboot(self):
self.run_command('host-action sample-host --action reboot')
self.assert_called('GET', '/os-hosts/sample-host/reboot')
def test_hypervisor_list(self):
self.run_command('hypervisor-list')
self.assert_called('GET', '/os-hypervisors')
def test_hypervisor_list_matching(self):
self.run_command('hypervisor-list --matching hyper')
self.assert_called('GET', '/os-hypervisors/hyper/search')
def test_hypervisor_servers(self):
self.run_command('hypervisor-servers hyper')
self.assert_called('GET', '/os-hypervisors/hyper/servers')
def test_hypervisor_show(self):
self.run_command('hypervisor-show 1234')
self.assert_called('GET', '/os-hypervisors/1234')
def test_hypervisor_uptime(self):
self.run_command('hypervisor-uptime 1234')
self.assert_called('GET', '/os-hypervisors/1234/uptime')
def test_hypervisor_stats(self):
self.run_command('hypervisor-stats')
self.assert_called('GET', '/os-hypervisors/statistics')
def test_quota_show(self):
self.run_command('quota-show test')
self.assert_called('GET', '/os-quota-sets/test')
def test_quota_defaults(self):
self.run_command('quota-defaults test')
self.assert_called('GET', '/os-quota-sets/test/defaults')
def test_quota_update(self):
self.run_command('quota-update test --instances=5')
self.assert_called('PUT', '/os-quota-sets/test')
def test_quota_class_show(self):
self.run_command('quota-class-show test')
self.assert_called('GET', '/os-quota-class-sets/test')
def test_quota_class_update(self):
self.run_command('quota-class-update test --instances=5')
self.assert_called('PUT', '/os-quota-class-sets/test')