387 lines
16 KiB
Python
387 lines
16 KiB
Python
# -*- coding: utf-8 -*-
|
|
# 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 random
|
|
import string
|
|
|
|
from tempest.lib import decorators
|
|
|
|
from novaclient.tests.functional import base
|
|
from novaclient.tests.functional.v2.legacy import test_servers
|
|
from novaclient.v2 import shell
|
|
|
|
|
|
class TestServersBootNovaClient(test_servers.TestServersBootNovaClient):
|
|
"""Servers boot functional tests."""
|
|
|
|
COMPUTE_API_VERSION = "2.latest"
|
|
|
|
|
|
class TestServersListNovaClient(test_servers.TestServersListNovaClient):
|
|
"""Servers list functional tests."""
|
|
|
|
COMPUTE_API_VERSION = "2.latest"
|
|
|
|
|
|
class TestServerLockV29(base.ClientTestBase):
|
|
|
|
COMPUTE_API_VERSION = "2.9"
|
|
|
|
def _show_server_and_check_lock_attr(self, server, value):
|
|
output = self.nova("show %s" % server.id)
|
|
self.assertEqual(str(value),
|
|
self._get_value_from_the_table(output, "locked"))
|
|
|
|
def test_attribute_presented(self):
|
|
# prepare
|
|
server = self._create_server()
|
|
|
|
# testing
|
|
self._show_server_and_check_lock_attr(server, False)
|
|
|
|
self.nova("lock %s" % server.id)
|
|
self._show_server_and_check_lock_attr(server, True)
|
|
|
|
self.nova("unlock %s" % server.id)
|
|
self._show_server_and_check_lock_attr(server, False)
|
|
|
|
|
|
class TestServersDescription(base.ClientTestBase):
|
|
|
|
COMPUTE_API_VERSION = "2.19"
|
|
|
|
def _boot_server_with_description(self):
|
|
descr = "Some words about this test VM."
|
|
server = self._create_server(description=descr)
|
|
|
|
self.assertEqual(descr, server.description)
|
|
|
|
return server, descr
|
|
|
|
def test_create(self):
|
|
# Add a description to the tests that create a server
|
|
server, descr = self._boot_server_with_description()
|
|
output = self.nova("show %s" % server.id)
|
|
self.assertEqual(descr, self._get_value_from_the_table(output,
|
|
"description"))
|
|
|
|
def test_list_servers_with_description(self):
|
|
# Check that the description is returned as part of server details
|
|
# for a server list
|
|
server, descr = self._boot_server_with_description()
|
|
output = self.nova("list --fields description")
|
|
self.assertEqual(server.id,
|
|
self._get_column_value_from_single_row_table(
|
|
output, "ID"))
|
|
self.assertEqual(descr,
|
|
self._get_column_value_from_single_row_table(
|
|
output, "Description"))
|
|
|
|
@decorators.skip_because(bug="1694371")
|
|
def test_rebuild(self):
|
|
# Add a description to the tests that rebuild a server
|
|
server, descr = self._boot_server_with_description()
|
|
descr = "New description for rebuilt VM."
|
|
self.nova("rebuild --description '%s' %s %s" %
|
|
(descr, server.id, self.image.name))
|
|
shell._poll_for_status(
|
|
self.client.servers.get, server.id,
|
|
'rebuild', ['active'])
|
|
output = self.nova("show %s" % server.id)
|
|
self.assertEqual(descr, self._get_value_from_the_table(output,
|
|
"description"))
|
|
|
|
def test_remove_description(self):
|
|
# Remove description from server booted with it
|
|
server, descr = self._boot_server_with_description()
|
|
self.nova("update %s --description ''" % server.id)
|
|
output = self.nova("show %s" % server.id)
|
|
self.assertEqual("-", self._get_value_from_the_table(output,
|
|
"description"))
|
|
|
|
def test_add_remove_description_on_existing_server(self):
|
|
# Set and remove the description on an existing server
|
|
server = self._create_server()
|
|
descr = "Add a description for previously-booted VM."
|
|
self.nova("update %s --description '%s'" % (server.id, descr))
|
|
output = self.nova("show %s" % server.id)
|
|
self.assertEqual(descr, self._get_value_from_the_table(output,
|
|
"description"))
|
|
self.nova("update %s --description ''" % server.id)
|
|
output = self.nova("show %s" % server.id)
|
|
self.assertEqual("-", self._get_value_from_the_table(output,
|
|
"description"))
|
|
|
|
def test_update_with_description_longer_than_255_symbols(self):
|
|
# Negative case for description longer than 255 characters
|
|
server = self._create_server()
|
|
descr = ''.join(random.choice(string.ascii_letters)
|
|
for i in range(256))
|
|
output = self.nova("update %s --description '%s'" % (server.id, descr),
|
|
fail_ok=True, merge_stderr=True)
|
|
self.assertIn("ERROR (BadRequest): Invalid input for field/attribute"
|
|
" description. Value: %s. '%s' is too long (HTTP 400)"
|
|
% (descr, descr), output)
|
|
|
|
|
|
class TestServersTagsV226(base.ClientTestBase):
|
|
|
|
COMPUTE_API_VERSION = "2.26"
|
|
|
|
def _boot_server_with_tags(self, tags=["t1", "t2"]):
|
|
uuid = self._create_server().id
|
|
self.client.servers.set_tags(uuid, tags)
|
|
return uuid
|
|
|
|
def test_show(self):
|
|
uuid = self._boot_server_with_tags()
|
|
output = self.nova("show %s" % uuid)
|
|
self.assertEqual('["t1", "t2"]', self._get_value_from_the_table(
|
|
output, "tags"))
|
|
|
|
def test_unicode_tag_correctly_displayed(self):
|
|
"""Regression test for bug #1669683.
|
|
|
|
List and dict fields with unicode cannot be correctly
|
|
displayed.
|
|
|
|
Ensure that once we fix this it doesn't regress.
|
|
"""
|
|
# create an instance with chinese tag
|
|
uuid = self._boot_server_with_tags(tags=["中文标签"])
|
|
output = self.nova("show %s" % uuid)
|
|
self.assertEqual('["中文标签"]', self._get_value_from_the_table(
|
|
output, "tags"))
|
|
|
|
def test_list(self):
|
|
uuid = self._boot_server_with_tags()
|
|
output = self.nova("server-tag-list %s" % uuid)
|
|
tags = self._get_list_of_values_from_single_column_table(
|
|
output, "Tag")
|
|
self.assertEqual(["t1", "t2"], tags)
|
|
|
|
def test_add(self):
|
|
uuid = self._boot_server_with_tags()
|
|
self.nova("server-tag-add %s t3" % uuid)
|
|
self.assertEqual(["t1", "t2", "t3"],
|
|
self.client.servers.tag_list(uuid))
|
|
|
|
def test_add_many(self):
|
|
uuid = self._boot_server_with_tags()
|
|
self.nova("server-tag-add %s t3 t4" % uuid)
|
|
self.assertEqual(["t1", "t2", "t3", "t4"],
|
|
self.client.servers.tag_list(uuid))
|
|
|
|
def test_set(self):
|
|
uuid = self._boot_server_with_tags()
|
|
self.nova("server-tag-set %s t3 t4" % uuid)
|
|
self.assertEqual(["t3", "t4"], self.client.servers.tag_list(uuid))
|
|
|
|
def test_delete(self):
|
|
uuid = self._boot_server_with_tags()
|
|
self.nova("server-tag-delete %s t2" % uuid)
|
|
self.assertEqual(["t1"], self.client.servers.tag_list(uuid))
|
|
|
|
def test_delete_many(self):
|
|
uuid = self._boot_server_with_tags()
|
|
self.nova("server-tag-delete %s t1 t2" % uuid)
|
|
self.assertEqual([], self.client.servers.tag_list(uuid))
|
|
|
|
def test_delete_all(self):
|
|
uuid = self._boot_server_with_tags()
|
|
self.nova("server-tag-delete-all %s" % uuid)
|
|
self.assertEqual([], self.client.servers.tag_list(uuid))
|
|
|
|
|
|
class TestServersAutoAllocateNetworkCLI(base.ClientTestBase):
|
|
|
|
COMPUTE_API_VERSION = '2.37'
|
|
|
|
def _find_network_in_table(self, table):
|
|
# Example:
|
|
# +-----------------+-----------------------------------+
|
|
# | Property | Value |
|
|
# +-----------------+-----------------------------------+
|
|
# | private network | 192.168.154.128 |
|
|
# +-----------------+-----------------------------------+
|
|
for line in table.split('\n'):
|
|
if '|' in line:
|
|
l_property, l_value = line.split('|')[1:3]
|
|
if ' network' in l_property.strip():
|
|
return ' '.join(l_property.strip().split()[:-1])
|
|
|
|
def test_boot_server_with_auto_network(self):
|
|
"""Tests that the CLI defaults to 'auto' when --nic isn't specified.
|
|
"""
|
|
# check to see if multiple networks are available because if so we
|
|
# have to skip this test as auto will fail with a 409 conflict as it's
|
|
# an ambiguous request and nova won't know which network to pick
|
|
if self.multiple_networks:
|
|
# we could potentially get around this by extending TenantTestBase
|
|
self.skipTest('multiple networks available')
|
|
server_info = self.nova('boot', params=(
|
|
'%(name)s --flavor %(flavor)s --poll '
|
|
'--image %(image)s ' % {'name': self.name_generate(),
|
|
'flavor': self.flavor.id,
|
|
'image': self.image.id}))
|
|
server_id = self._get_value_from_the_table(server_info, 'id')
|
|
self.addCleanup(self.wait_for_resource_delete,
|
|
server_id, self.client.servers)
|
|
self.addCleanup(self.client.servers.delete, server_id)
|
|
# get the server details to verify there is a network, we don't care
|
|
# what the network name is, we just want to see an entry show up
|
|
server_info = self.nova('show', params=server_id)
|
|
network = self._find_network_in_table(server_info)
|
|
self.assertIsNotNone(
|
|
network, 'Auto-allocated network not found: %s' % server_info)
|
|
|
|
def test_boot_server_with_no_network(self):
|
|
"""Tests that '--nic none' is honored.
|
|
"""
|
|
server_info = self.nova('boot', params=(
|
|
'%(name)s --flavor %(flavor)s --poll '
|
|
'--image %(image)s --nic none' %
|
|
{'name': self.name_generate(),
|
|
'flavor': self.flavor.id,
|
|
'image': self.image.id}))
|
|
server_id = self._get_value_from_the_table(server_info, 'id')
|
|
self.addCleanup(self.wait_for_resource_delete,
|
|
server_id, self.client.servers)
|
|
self.addCleanup(self.client.servers.delete, server_id)
|
|
# get the server details to verify there is not a network
|
|
server_info = self.nova('show', params=server_id)
|
|
network = self._find_network_in_table(server_info)
|
|
self.assertIsNone(
|
|
network, 'Unexpected network allocation: %s' % server_info)
|
|
|
|
|
|
class TestServersDetailsFlavorInfo(base.ClientTestBase):
|
|
|
|
COMPUTE_API_VERSION = '2.47'
|
|
|
|
def _validate_flavor_details(self, flavor_details, server_details):
|
|
# This is a mapping between the keys used in the flavor GET response
|
|
# and the keys used for the flavor information embedded in the server
|
|
# details.
|
|
flavor_key_mapping = {
|
|
"OS-FLV-EXT-DATA:ephemeral": "flavor:ephemeral",
|
|
"disk": "flavor:disk",
|
|
"extra_specs": "flavor:extra_specs",
|
|
"name": "flavor:original_name",
|
|
"ram": "flavor:ram",
|
|
"swap": "flavor:swap",
|
|
"vcpus": "flavor:vcpus",
|
|
}
|
|
|
|
for key in flavor_key_mapping:
|
|
flavor_val = self._get_value_from_the_table(
|
|
flavor_details, key)
|
|
server_flavor_val = self._get_value_from_the_table(
|
|
server_details, flavor_key_mapping[key])
|
|
if key == "swap" and flavor_val == "":
|
|
# "flavor-show" displays zero swap as empty string.
|
|
flavor_val = '0'
|
|
self.assertEqual(flavor_val, server_flavor_val)
|
|
|
|
def _setup_extra_specs(self, flavor_id):
|
|
extra_spec_key = "dummykey"
|
|
self.nova('flavor-key', params=('%(flavor)s set %(key)s=dummyval' %
|
|
{'flavor': flavor_id,
|
|
'key': extra_spec_key}))
|
|
unset_params = ('%(flavor)s unset %(key)s' %
|
|
{'flavor': flavor_id, 'key': extra_spec_key})
|
|
self.addCleanup(self.nova, 'flavor-key', params=unset_params)
|
|
|
|
def test_show(self):
|
|
self._setup_extra_specs(self.flavor.id)
|
|
uuid = self._create_server().id
|
|
server_output = self.nova("show %s" % uuid)
|
|
flavor_output = self.nova("flavor-show %s" % self.flavor.id)
|
|
self._validate_flavor_details(flavor_output, server_output)
|
|
|
|
def test_show_minimal(self):
|
|
uuid = self._create_server().id
|
|
server_output = self.nova("show --minimal %s" % uuid)
|
|
server_output_flavor = self._get_value_from_the_table(
|
|
server_output, 'flavor')
|
|
self.assertEqual(self.flavor.name, server_output_flavor)
|
|
|
|
def test_list(self):
|
|
self._setup_extra_specs(self.flavor.id)
|
|
self._create_server()
|
|
server_output = self.nova("list --fields flavor:disk")
|
|
# namespaced fields get reformatted slightly as column names
|
|
server_flavor_val = self._get_column_value_from_single_row_table(
|
|
server_output, 'flavor: Disk')
|
|
flavor_output = self.nova("flavor-show %s" % self.flavor.id)
|
|
flavor_val = self._get_value_from_the_table(flavor_output, 'disk')
|
|
self.assertEqual(flavor_val, server_flavor_val)
|
|
|
|
|
|
class TestInterfaceAttach(base.ClientTestBase):
|
|
|
|
COMPUTE_API_VERSION = '2.latest'
|
|
|
|
def test_interface_attach(self):
|
|
server = self._create_server()
|
|
output = self.nova("interface-attach --net-id %s %s" %
|
|
(self.network.id, server.id))
|
|
|
|
for key in ('ip_address', 'mac_addr', 'port_id', 'port_state'):
|
|
self._get_value_from_the_table(output, key)
|
|
|
|
self.assertEqual(
|
|
self.network.id,
|
|
self._get_value_from_the_table(output, 'net_id'))
|
|
|
|
|
|
class TestServeRebuildV274(base.ClientTestBase):
|
|
|
|
COMPUTE_API_VERSION = '2.74'
|
|
REBUILD_FIELDS = ["OS-DCF:diskConfig", "accessIPv4", "accessIPv6",
|
|
"adminPass", "created", "description",
|
|
"flavor", "hostId", "id", "image", "key_name",
|
|
"locked", "locked_reason", "metadata", "name",
|
|
"progress", "server_groups", "status", "tags",
|
|
"tenant_id", "trusted_image_certificates", "updated",
|
|
"user_data", "user_id"]
|
|
|
|
def test_rebuild(self):
|
|
server = self._create_server()
|
|
output = self.nova("rebuild %s %s" % (server.id, self.image.name))
|
|
for field in self.REBUILD_FIELDS:
|
|
self.assertIn(field, output)
|
|
|
|
|
|
class TestServeRebuildV275(TestServeRebuildV274):
|
|
|
|
COMPUTE_API_VERSION = '2.75'
|
|
REBUILD_FIELDS_V275 = ['OS-EXT-AZ:availability_zone', 'config_drive',
|
|
'OS-EXT-SRV-ATTR:host',
|
|
'OS-EXT-SRV-ATTR:hypervisor_hostname',
|
|
'OS-EXT-SRV-ATTR:instance_name',
|
|
'OS-EXT-SRV-ATTR:hostname',
|
|
'OS-EXT-SRV-ATTR:kernel_id',
|
|
'OS-EXT-SRV-ATTR:launch_index',
|
|
'OS-EXT-SRV-ATTR:ramdisk_id',
|
|
'OS-EXT-SRV-ATTR:reservation_id',
|
|
'OS-EXT-SRV-ATTR:root_device_name',
|
|
'host_status',
|
|
'OS-SRV-USG:launched_at',
|
|
'OS-SRV-USG:terminated_at',
|
|
'OS-EXT-STS:task_state', 'OS-EXT-STS:vm_state',
|
|
'OS-EXT-STS:power_state', 'security_groups',
|
|
'os-extended-volumes:volumes_attached']
|
|
|
|
REBUILD_FIELDS = TestServeRebuildV274.REBUILD_FIELDS + REBUILD_FIELDS_V275
|