Merge "Add Test to Create Port with no security groups"
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index f729436..a9c72fb 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -32,6 +32,10 @@
# Get max limit value
max_meta = self.client.get_specific_absolute_limit('maxImageMeta')
+ # No point in running this test if there is no limit.
+ if int(max_meta) == -1:
+ raise self.skipException('no limit for maxImageMeta')
+
# Create server should fail, since we are passing > metadata Limit!
max_meta_data = int(max_meta) + 1
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index 8b074fd..ee1e652 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -124,6 +124,9 @@
# tenant.
_, quota_set = self.quotas.get_quota_set(self.tenant_id)
quota_metadata = quota_set['metadata_items']
+ if quota_metadata == -1:
+ raise self.skipException("No limit for metadata_items")
+
req_metadata = {}
for num in range(1, quota_metadata + 2):
req_metadata['key' + str(num)] = 'val' + str(num)
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 4e6dcda..f44d158 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import base64
import sys
import testtools
@@ -166,18 +165,10 @@
def test_rebuild_non_existent_server(self):
# Rebuild a non existent server
nonexistent_server = data_utils.rand_uuid()
- meta = {'rebuild': 'server'}
- new_name = data_utils.rand_name('server')
- file_contents = 'Test server rebuild.'
- personality = [{'path': '/etc/rebuild.txt',
- 'contents': base64.b64encode(file_contents)}]
self.assertRaises(exceptions.NotFound,
self.client.rebuild,
nonexistent_server,
- self.image_ref_alt,
- name=new_name, meta=meta,
- personality=personality,
- adminPass='rebuild')
+ self.image_ref_alt)
@test.attr(type=['negative', 'gate'])
def test_create_numeric_server_name(self):
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
new file mode 100644
index 0000000..5bc63d0
--- /dev/null
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -0,0 +1,389 @@
+# Copyright 2014 OpenStack Foundation
+# 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 netaddr
+import random
+
+from tempest.api.network import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import exceptions
+
+CONF = config.CONF
+
+
+class NetworksTestDHCPv6(base.BaseNetworkTest):
+ _interface = 'json'
+ _ip_version = 6
+
+ """ Test DHCPv6 specific features using SLAAC, stateless and
+ stateful settings for subnets. Also it shall check dual-stack
+ functionality (IPv4 + IPv6 together).
+ The tests include:
+ generating of SLAAC EUI-64 address in subnets with various settings
+ receiving SLAAC addresses in combinations of various subnets
+ receiving stateful IPv6 addresses
+ addressing in subnets with router
+ """
+
+ @classmethod
+ def resource_setup(cls):
+ msg = None
+ if not CONF.network_feature_enabled.ipv6:
+ msg = "IPv6 is not enabled"
+ elif not CONF.network_feature_enabled.ipv6_subnet_attributes:
+ msg = "DHCPv6 attributes are not enabled."
+ if msg:
+ raise cls.skipException(msg)
+ super(NetworksTestDHCPv6, cls).resource_setup()
+ cls.network = cls.create_network()
+
+ def _remove_from_list_by_index(self, things_list, elem):
+ for index, i in enumerate(things_list):
+ if i['id'] == elem['id']:
+ break
+ del things_list[index]
+
+ def _clean_network(self):
+ resp, body = self.client.list_ports()
+ ports = body['ports']
+ for port in ports:
+ if (port['device_owner'] == 'network:router_interface'
+ and port['device_id'] in [r['id'] for r in self.routers]):
+ self.client.remove_router_interface_with_port_id(
+ port['device_id'], port['id']
+ )
+ else:
+ if port['id'] in [p['id'] for p in self.ports]:
+ self.client.delete_port(port['id'])
+ self._remove_from_list_by_index(self.ports, port)
+ resp, body = self.client.list_subnets()
+ subnets = body['subnets']
+ for subnet in subnets:
+ if subnet['id'] in [s['id'] for s in self.subnets]:
+ self.client.delete_subnet(subnet['id'])
+ self._remove_from_list_by_index(self.subnets, subnet)
+ resp, body = self.client.list_routers()
+ routers = body['routers']
+ for router in routers:
+ if router['id'] in [r['id'] for r in self.routers]:
+ self.client.delete_router(router['id'])
+ self._remove_from_list_by_index(self.routers, router)
+
+ def _get_ips_from_subnet(self, **kwargs):
+ subnet = self.create_subnet(self.network, **kwargs)
+ port_mac = data_utils.rand_mac_address()
+ port = self.create_port(self.network, mac_address=port_mac)
+ real_ip = next(iter(port['fixed_ips']), None)['ip_address']
+ eui_ip = data_utils.get_ipv6_addr_by_EUI64(subnet['cidr'],
+ port_mac).format()
+ return real_ip, eui_ip
+
+ def test_dhcpv6_stateless_eui64(self):
+ """When subnets configured with RAs SLAAC (AOM=100) and DHCP stateless
+ (AOM=110) both for radvd and dnsmasq, port shall receive IP address
+ calculated from its MAC.
+ """
+ for ra_mode, add_mode in (
+ ('slaac', 'slaac'),
+ ('dhcpv6-stateless', 'dhcpv6-stateless'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
+ self._clean_network()
+ self.assertEqual(eui_ip, real_ip,
+ ('Real port IP is %s, but shall be %s when '
+ 'ipv6_ra_mode=%s and ipv6_address_mode=%s') % (
+ real_ip, eui_ip, ra_mode, add_mode))
+
+ def test_dhcpv6_stateless_no_ra(self):
+ """When subnets configured with dnsmasq SLAAC and DHCP stateless
+ and there is no radvd, port shall receive IP address calculated
+ from its MAC and mask of subnet.
+ """
+ for ra_mode, add_mode in (
+ (None, 'slaac'),
+ (None, 'dhcpv6-stateless'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
+ self._clean_network()
+ self.assertEqual(eui_ip, real_ip,
+ ('Real port IP %s shall be equal to EUI-64 %s'
+ 'when ipv6_ra_mode=%s,ipv6_address_mode=%s') % (
+ real_ip, eui_ip,
+ ra_mode if ra_mode else "Off",
+ add_mode if add_mode else "Off"))
+
+ def test_dhcpv6_invalid_options(self):
+ """Different configurations for radvd and dnsmasq are not allowed"""
+ for ra_mode, add_mode in (
+ ('dhcpv6-stateless', 'dhcpv6-stateful'),
+ ('dhcpv6-stateless', 'slaac'),
+ ('slaac', 'dhcpv6-stateful'),
+ ('dhcpv6-stateful', 'dhcpv6-stateless'),
+ ('dhcpv6-stateful', 'slaac'),
+ ('slaac', 'dhcpv6-stateless'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ self.assertRaises(exceptions.BadRequest,
+ self.create_subnet,
+ self.network,
+ **kwargs)
+
+ def test_dhcpv6_stateless_no_ra_no_dhcp(self):
+ """If no radvd option and no dnsmasq option is configured
+ port shall receive IP from fixed IPs list of subnet.
+ """
+ real_ip, eui_ip = self._get_ips_from_subnet()
+ self._clean_network()
+ self.assertNotEqual(eui_ip, real_ip,
+ ('Real port IP %s equal to EUI-64 %s when '
+ 'ipv6_ra_mode=Off and ipv6_address_mode=Off,'
+ 'but shall be taken from fixed IPs') % (
+ real_ip, eui_ip))
+
+ def test_dhcpv6_two_subnets(self):
+ """When one IPv6 subnet configured with dnsmasq SLAAC or DHCP stateless
+ and other IPv6 is with DHCP stateful, port shall receive EUI-64 IP
+ addresses from first subnet and DHCP address from second one.
+ Order of subnet creating should be unimportant.
+ """
+ for order in ("slaac_first", "dhcp_first"):
+ for ra_mode, add_mode in (
+ ('slaac', 'slaac'),
+ ('dhcpv6-stateless', 'dhcpv6-stateless'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ kwargs_dhcp = {'ipv6_address_mode': 'dhcpv6-stateful'}
+ if order == "slaac_first":
+ subnet_slaac = self.create_subnet(self.network, **kwargs)
+ subnet_dhcp = self.create_subnet(
+ self.network, **kwargs_dhcp)
+ else:
+ subnet_dhcp = self.create_subnet(
+ self.network, **kwargs_dhcp)
+ subnet_slaac = self.create_subnet(self.network, **kwargs)
+ port_mac = data_utils.rand_mac_address()
+ dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
+ eui_ip = data_utils.get_ipv6_addr_by_EUI64(
+ subnet_slaac['cidr'],
+ port_mac
+ ).format()
+ # TODO(sergsh): remove this when 1219795 is fixed
+ dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
+ port = self.create_port(self.network, mac_address=port_mac)
+ real_ips = dict([(k['subnet_id'], k['ip_address'])
+ for k in port['fixed_ips']])
+ real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
+ for sub in subnet_dhcp,
+ subnet_slaac]
+ self.client.delete_port(port['id'])
+ self.ports.pop()
+ _, body = self.client.list_ports()
+ ports_id_list = [i['id'] for i in body['ports']]
+ self.assertNotIn(port['id'], ports_id_list)
+ self._clean_network()
+ self.assertEqual(real_eui_ip,
+ eui_ip,
+ 'Real IP is {0}, but shall be {1}'.format(
+ real_eui_ip,
+ eui_ip))
+ self.assertIn(
+ real_dhcp_ip, dhcp_ip,
+ 'Real IP is {0}, but shall be one from {1}'.format(
+ real_dhcp_ip,
+ str(dhcp_ip)))
+
+ def test_dhcpv6_64_subnets(self):
+ """When one IPv6 subnet configured with dnsmasq SLAAC or DHCP stateless
+ and other IPv4 is with DHCP of IPv4, port shall receive EUI-64 IP
+ addresses from first subnet and IPv4 DHCP address from second one.
+ Order of subnet creating should be unimportant.
+ """
+ for order in ("slaac_first", "dhcp_first"):
+ for ra_mode, add_mode in (
+ ('slaac', 'slaac'),
+ ('dhcpv6-stateless', 'dhcpv6-stateless'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ if order == "slaac_first":
+ subnet_slaac = self.create_subnet(self.network, **kwargs)
+ subnet_dhcp = self.create_subnet(
+ self.network, ip_version=4)
+ else:
+ subnet_dhcp = self.create_subnet(
+ self.network, ip_version=4)
+ subnet_slaac = self.create_subnet(self.network, **kwargs)
+ port_mac = data_utils.rand_mac_address()
+ dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
+ eui_ip = data_utils.get_ipv6_addr_by_EUI64(
+ subnet_slaac['cidr'],
+ port_mac
+ ).format()
+ # TODO(sergsh): remove this when 1219795 is fixed
+ dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
+ port = self.create_port(self.network, mac_address=port_mac)
+ real_ips = dict([(k['subnet_id'], k['ip_address'])
+ for k in port['fixed_ips']])
+ real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
+ for sub in subnet_dhcp,
+ subnet_slaac]
+ self._clean_network()
+ self.assertTrue({real_eui_ip,
+ real_dhcp_ip}.issubset([eui_ip] + dhcp_ip))
+ self.assertEqual(real_eui_ip,
+ eui_ip,
+ 'Real IP is {0}, but shall be {1}'.format(
+ real_eui_ip,
+ eui_ip))
+ self.assertIn(
+ real_dhcp_ip, dhcp_ip,
+ 'Real IP is {0}, but shall be one from {1}'.format(
+ real_dhcp_ip,
+ str(dhcp_ip)))
+
+ def test_dhcp_stateful(self):
+ """With all options below, DHCPv6 shall allocate first
+ address from subnet pool to port.
+ """
+ for ra_mode, add_mode in (
+ ('dhcpv6-stateful', 'dhcpv6-stateful'),
+ ('dhcpv6-stateful', None),
+ (None, 'dhcpv6-stateful'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ subnet = self.create_subnet(self.network, **kwargs)
+ port = self.create_port(self.network)
+ port_ip = next(iter(port['fixed_ips']), None)['ip_address']
+ dhcp_ip = subnet["allocation_pools"][0]["start"]
+ # TODO(sergsh): remove this when 1219795 is fixed
+ dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
+ self._clean_network()
+ self.assertIn(
+ port_ip, dhcp_ip,
+ 'Real IP is {0}, but shall be one from {1}'.format(
+ port_ip,
+ str(dhcp_ip)))
+
+ def test_dhcp_stateful_fixedips(self):
+ """With all options below, port shall be able to get
+ requested IP from fixed IP range not depending on
+ DHCP stateful (not SLAAC!) settings configured.
+ """
+ for ra_mode, add_mode in (
+ ('dhcpv6-stateful', 'dhcpv6-stateful'),
+ ('dhcpv6-stateful', None),
+ (None, 'dhcpv6-stateful'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ subnet = self.create_subnet(self.network, **kwargs)
+ ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
+ subnet["allocation_pools"][0]["end"])
+ ip = netaddr.IPAddress(random.randrange(ip_range.first,
+ ip_range.last)).format()
+ port = self.create_port(self.network,
+ fixed_ips=[{'subnet_id': subnet['id'],
+ 'ip_address': ip}])
+ port_ip = next(iter(port['fixed_ips']), None)['ip_address']
+ self._clean_network()
+ self.assertEqual(port_ip, ip,
+ ("Port IP %s is not as fixed IP from "
+ "port create request: %s") % (
+ port_ip, ip))
+
+ def test_dhcp_stateful_fixedips_outrange(self):
+ """When port gets IP address from fixed IP range it
+ shall be checked if it's from subnets range.
+ """
+ kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
+ 'ipv6_address_mode': 'dhcpv6-stateful'}
+ subnet = self.create_subnet(self.network, **kwargs)
+ ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
+ subnet["allocation_pools"][0]["end"])
+ ip = netaddr.IPAddress(random.randrange(
+ ip_range.last + 1, ip_range.last + 10)).format()
+ self.assertRaisesRegexp(exceptions.BadRequest,
+ "not a valid IP for the defined subnet",
+ self.create_port,
+ self.network,
+ fixed_ips=[{'subnet_id': subnet['id'],
+ 'ip_address': ip}])
+
+ def test_dhcp_stateful_fixedips_duplicate(self):
+ """When port gets IP address from fixed IP range it
+ shall be checked if it's not duplicate.
+ """
+ kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
+ 'ipv6_address_mode': 'dhcpv6-stateful'}
+ subnet = self.create_subnet(self.network, **kwargs)
+ ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
+ subnet["allocation_pools"][0]["end"])
+ ip = netaddr.IPAddress(random.randrange(
+ ip_range.first, ip_range.last)).format()
+ self.create_port(self.network,
+ fixed_ips=[
+ {'subnet_id': subnet['id'],
+ 'ip_address': ip}])
+ self.assertRaisesRegexp(exceptions.Conflict,
+ "object with that identifier already exists",
+ self.create_port,
+ self.network,
+ fixed_ips=[{'subnet_id': subnet['id'],
+ 'ip_address': ip}])
+
+ def _create_subnet_router(self, kwargs):
+ subnet = self.create_subnet(self.network, **kwargs)
+ router = self.create_router(
+ router_name=data_utils.rand_name("routerv6-"),
+ admin_state_up=True)
+ port = self.create_router_interface(router['id'],
+ subnet['id'])
+ _, body = self.client.show_port(port['port_id'])
+ return subnet, body['port']
+
+ def test_dhcp_stateful_router(self):
+ """With all options below the router interface shall
+ receive DHCPv6 IP address from allocation pool.
+ """
+ for ra_mode, add_mode in (
+ ('dhcpv6-stateful', 'dhcpv6-stateful'),
+ ('dhcpv6-stateful', None),
+ (None, 'dhcpv6-stateful'),
+ ):
+ kwargs = {'ipv6_ra_mode': ra_mode,
+ 'ipv6_address_mode': add_mode}
+ kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ subnet, port = self._create_subnet_router(kwargs)
+ port_ip = next(iter(port['fixed_ips']), None)['ip_address']
+ self._clean_network()
+ self.assertEqual(port_ip, subnet['gateway_ip'],
+ ("Port IP %s is not as first IP from "
+ "subnets allocation pool: %s") % (
+ port_ip, subnet['gateway_ip']))
+
+ def tearDown(self):
+ self._clean_network()
+ super(NetworksTestDHCPv6, self).tearDown()
diff --git a/tempest/common/utils/data_utils.py b/tempest/common/utils/data_utils.py
index 5a29ea0..d441778 100644
--- a/tempest/common/utils/data_utils.py
+++ b/tempest/common/utils/data_utils.py
@@ -14,6 +14,7 @@
# under the License.
import itertools
+import netaddr
import random
import uuid
@@ -79,3 +80,22 @@
"""
return ''.join([chr(random.randint(0, 255))
for i in range(size)])
+
+
+def get_ipv6_addr_by_EUI64(cidr, mac):
+ # Check if the prefix is IPv4 address
+ is_ipv4 = netaddr.valid_ipv4(cidr)
+ if is_ipv4:
+ msg = "Unable to generate IP address by EUI64 for IPv4 prefix"
+ raise TypeError(msg)
+ try:
+ eui64 = int(netaddr.EUI(mac).eui64())
+ prefix = netaddr.IPNetwork(cidr)
+ return netaddr.IPAddress(prefix.first + eui64 ^ (1 << 57))
+ except (ValueError, netaddr.AddrFormatError):
+ raise TypeError('Bad prefix or mac format for generating IPv6 '
+ 'address by EUI-64: %(prefix)s, %(mac)s:'
+ % {'prefix': cidr, 'mac': mac})
+ except TypeError:
+ raise TypeError('Bad prefix type for generate IPv6 address by '
+ 'EUI-64: %s' % cidr)
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 2014293..35f6689 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -67,7 +67,7 @@
response = urllib2.urlopen(CONF.dashboard.dashboard_url)
self.assertIn("Log In", response.read())
- def user_login(self):
+ def user_login(self, username, password):
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
response = self.opener.open(CONF.dashboard.dashboard_url).read()
@@ -79,8 +79,8 @@
req = urllib2.Request(CONF.dashboard.login_url)
req.add_header('Content-type', 'application/x-www-form-urlencoded')
req.add_header('Referer', CONF.dashboard.dashboard_url)
- params = {'username': CONF.identity.username,
- 'password': CONF.identity.password,
+ params = {'username': username,
+ 'password': password,
'region': parser.region,
'csrfmiddlewaretoken': parser.csrf_token}
self.opener.open(req, urllib.urlencode(params))
@@ -91,6 +91,7 @@
@test.services('dashboard')
def test_basic_scenario(self):
+ creds = self.credentials()
self.check_login_page()
- self.user_login()
+ self.user_login(creds.username, creds.password)
self.check_home_page()
diff --git a/tempest/tests/test_credentials.py b/tempest/tests/test_credentials.py
index ea576c4..fc80fe2 100644
--- a/tempest/tests/test_credentials.py
+++ b/tempest/tests/test_credentials.py
@@ -24,7 +24,6 @@
from tempest import exceptions
from tempest.tests import base
from tempest.tests import fake_config
-from tempest.tests import fake_http
from tempest.tests import fake_identity
@@ -39,8 +38,6 @@
def setUp(self):
super(CredentialsTests, self).setUp()
- self.fake_http = fake_http.fake_httplib2(return_type=200)
- self.stubs.Set(http.ClosingHttp, 'request', self.fake_http.request)
self.useFixture(fake_config.ConfigFixture())
self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
@@ -83,7 +80,6 @@
def setUp(self):
super(KeystoneV2CredentialsTests, self).setUp()
self.stubs.Set(http.ClosingHttp, 'request', self.identity_response)
- self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
def _verify_credentials(self, credentials_class, filled=True,
creds_dict=None):