Support IPv6
This commit is contained in:
parent
0a93a9298d
commit
c5c58cb20d
@ -87,7 +87,7 @@ flags.DECLARE('num_networks', 'nova.network.manager')
|
||||
flags.DECLARE('network_size', 'nova.network.manager')
|
||||
flags.DECLARE('vlan_start', 'nova.network.manager')
|
||||
flags.DECLARE('vpn_start', 'nova.network.manager')
|
||||
|
||||
flags.DECLARE('fixed_range_v6', 'nova.network.manager')
|
||||
|
||||
class VpnCommands(object):
|
||||
"""Class for managing VPNs."""
|
||||
@ -411,11 +411,11 @@ class NetworkCommands(object):
|
||||
"""Class for managing networks."""
|
||||
|
||||
def create(self, fixed_range=None, num_networks=None,
|
||||
network_size=None, vlan_start=None, vpn_start=None):
|
||||
network_size=None, vlan_start=None, vpn_start=None,fixed_range_v6=None):
|
||||
"""Creates fixed ips for host by range
|
||||
arguments: [fixed_range=FLAG], [num_networks=FLAG],
|
||||
[network_size=FLAG], [vlan_start=FLAG],
|
||||
[vpn_start=FLAG]"""
|
||||
[vpn_start=FLAG],[fixed_range_v6=FLAG]"""
|
||||
if not fixed_range:
|
||||
fixed_range = FLAGS.fixed_range
|
||||
if not num_networks:
|
||||
@ -426,11 +426,15 @@ class NetworkCommands(object):
|
||||
vlan_start = FLAGS.vlan_start
|
||||
if not vpn_start:
|
||||
vpn_start = FLAGS.vpn_start
|
||||
if not fixed_range_v6:
|
||||
fixed_range_v6 = FLAGS.fixed_range_v6
|
||||
net_manager = utils.import_object(FLAGS.network_manager)
|
||||
net_manager.create_networks(context.get_admin_context(),
|
||||
fixed_range, int(num_networks),
|
||||
int(network_size), int(vlan_start),
|
||||
int(vpn_start))
|
||||
int(vpn_start),fixed_range_v6)
|
||||
|
||||
|
||||
|
||||
CATEGORIES = [
|
||||
('user', UserCommands),
|
||||
|
37
contrib/boto_v6/__init__.py
Normal file
37
contrib/boto_v6/__init__.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright (c) 2006-2010 Mitch Garnaat http://garnaat.org/
|
||||
# Copyright (c) 2010, Eucalyptus Systems, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish, dis-
|
||||
# tribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
# persons to whom the Software is furnished to do so, subject to the fol-
|
||||
# lowing conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
|
||||
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
|
||||
def connect_ec2(aws_access_key_id=None, aws_secret_access_key=None, **kwargs):
|
||||
"""
|
||||
:type aws_access_key_id: string
|
||||
:param aws_access_key_id: Your AWS Access Key ID
|
||||
|
||||
:type aws_secret_access_key: string
|
||||
:param aws_secret_access_key: Your AWS Secret Access Key
|
||||
|
||||
:rtype: :class:`boto.ec2.connection.EC2Connection`
|
||||
:return: A connection to Amazon's EC2
|
||||
"""
|
||||
from boto_v6.ec2.connection import EC2ConnectionV6
|
||||
return EC2ConnectionV6(aws_access_key_id, aws_secret_access_key, **kwargs)
|
0
contrib/boto_v6/ec2/__init__.py
Normal file
0
contrib/boto_v6/ec2/__init__.py
Normal file
41
contrib/boto_v6/ec2/connection.py
Normal file
41
contrib/boto_v6/ec2/connection.py
Normal file
@ -0,0 +1,41 @@
|
||||
'''
|
||||
Created on 2010/12/20
|
||||
|
||||
@author: Nachi Ueno <ueno.nachi@lab.ntt.co.jp>
|
||||
'''
|
||||
import boto
|
||||
import boto.ec2
|
||||
from boto_v6.ec2.instance import ReservationV6
|
||||
|
||||
|
||||
class EC2ConnectionV6(boto.ec2.EC2Connection):
|
||||
'''
|
||||
EC2Connection for OpenStack IPV6 mode
|
||||
'''
|
||||
def get_all_instances(self, instance_ids=None, filters=None):
|
||||
"""
|
||||
Retrieve all the instances associated with your account.
|
||||
|
||||
:type instance_ids: list
|
||||
:param instance_ids: A list of strings of instance IDs
|
||||
|
||||
:type filters: dict
|
||||
:param filters: Optional filters that can be used to limit
|
||||
the results returned. Filters are provided
|
||||
in the form of a dictionary consisting of
|
||||
filter names as the key and filter values
|
||||
as the value. The set of allowable filter
|
||||
names/values is dependent on the request
|
||||
being performed. Check the EC2 API guide
|
||||
for details.
|
||||
|
||||
:rtype: list
|
||||
:return: A list of :class:`boto.ec2.instance.Reservation`
|
||||
"""
|
||||
params = {}
|
||||
if instance_ids:
|
||||
self.build_list_params(params, instance_ids, 'InstanceId')
|
||||
if filters:
|
||||
self.build_filter_params(params, filters)
|
||||
return self.get_list('DescribeInstances', params,
|
||||
[('item', ReservationV6)])
|
33
contrib/boto_v6/ec2/instance.py
Normal file
33
contrib/boto_v6/ec2/instance.py
Normal file
@ -0,0 +1,33 @@
|
||||
'''
|
||||
Created on 2010/12/20
|
||||
|
||||
@author: Nachi Ueno <ueno.nachi@lab.ntt.co.jp>
|
||||
'''
|
||||
import boto
|
||||
from boto.resultset import ResultSet
|
||||
from boto.ec2.instance import Reservation
|
||||
from boto.ec2.instance import Group
|
||||
from boto.ec2.instance import Instance
|
||||
|
||||
|
||||
class ReservationV6(Reservation):
|
||||
def startElement(self, name, attrs, connection):
|
||||
if name == 'instancesSet':
|
||||
self.instances = ResultSet([('item', InstanceV6)])
|
||||
return self.instances
|
||||
elif name == 'groupSet':
|
||||
self.groups = ResultSet([('item', Group)])
|
||||
return self.groups
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class InstanceV6(Instance):
|
||||
def __init__(self, connection=None):
|
||||
Instance.__init__(self, connection)
|
||||
self.public_dns_name_v6 = None
|
||||
|
||||
def endElement(self, name, value, connection):
|
||||
Instance.endElement(self, name, value, connection)
|
||||
if name == 'dnsNameV6':
|
||||
self.dns_name_v6 = value
|
@ -85,6 +85,10 @@ if [ "$CMD" == "install" ]; then
|
||||
sudo apt-get install -y python-twisted python-sqlalchemy python-mox python-greenlet python-carrot
|
||||
sudo apt-get install -y python-daemon python-eventlet python-gflags python-tornado python-ipy
|
||||
sudo apt-get install -y python-libvirt python-libxml2 python-routes
|
||||
#For IPV6
|
||||
sudo apt-get install -y python-netaddr
|
||||
sudo apt-get install -y radvd
|
||||
|
||||
if [ "$USE_MYSQL" == 1 ]; then
|
||||
cat <<MYSQL_PRESEED | debconf-set-selections
|
||||
mysql-server-5.1 mysql-server/root_password password $MYSQL_PASS
|
||||
@ -106,6 +110,8 @@ function screen_it {
|
||||
|
||||
if [ "$CMD" == "run" ]; then
|
||||
killall dnsmasq
|
||||
#For IPv6
|
||||
killall radvd
|
||||
screen -d -m -S nova -t nova
|
||||
sleep 1
|
||||
if [ "$USE_MYSQL" == 1 ]; then
|
||||
|
@ -31,7 +31,7 @@ import time
|
||||
|
||||
from nova import context
|
||||
import IPy
|
||||
|
||||
import urllib
|
||||
from nova import crypto
|
||||
from nova import db
|
||||
from nova import exception
|
||||
@ -307,6 +307,7 @@ class CloudController(object):
|
||||
values['group_id'] = source_security_group['id']
|
||||
elif cidr_ip:
|
||||
# If this fails, it throws an exception. This is what we want.
|
||||
cidr_ip = urllib.unquote(cidr_ip).decode()
|
||||
IPy.IP(cidr_ip)
|
||||
values['cidr'] = cidr_ip
|
||||
else:
|
||||
@ -635,10 +636,16 @@ class CloudController(object):
|
||||
if instance['fixed_ip']['floating_ips']:
|
||||
fixed = instance['fixed_ip']
|
||||
floating_addr = fixed['floating_ips'][0]['address']
|
||||
if instance['fixed_ip']['network'] and FLAGS.use_ipv6:
|
||||
i['dnsNameV6'] = utils.to_global_ipv6(
|
||||
instance['fixed_ip']['network']['cidr_v6'],
|
||||
instance['mac_address'])
|
||||
|
||||
i['privateDnsName'] = fixed_addr
|
||||
i['publicDnsName'] = floating_addr
|
||||
i['dnsName'] = i['publicDnsName'] or i['privateDnsName']
|
||||
i['keyName'] = instance['key_name']
|
||||
|
||||
if context.user.is_admin():
|
||||
i['keyName'] = '%s (%s, %s)' % (i['keyName'],
|
||||
instance['project_id'],
|
||||
|
@ -240,6 +240,9 @@ def fixed_ip_get_instance(context, address):
|
||||
"""Get an instance for a fixed ip by address."""
|
||||
return IMPL.fixed_ip_get_instance(context, address)
|
||||
|
||||
def fixed_ip_get_instance_v6(context, address):
|
||||
return IMPL.fixed_ip_get_instance_v6(context, address)
|
||||
|
||||
|
||||
def fixed_ip_get_network(context, address):
|
||||
"""Get a network for a fixed ip by address."""
|
||||
@ -298,6 +301,9 @@ def instance_get_fixed_address(context, instance_id):
|
||||
"""Get the fixed ip address of an instance."""
|
||||
return IMPL.instance_get_fixed_address(context, instance_id)
|
||||
|
||||
def instance_get_fixed_address_v6(context, instance_id):
|
||||
return IMPL.instance_get_fixed_address_v6(context, instance_id)
|
||||
|
||||
|
||||
def instance_get_floating_address(context, instance_id):
|
||||
"""Get the first floating ip address of an instance."""
|
||||
@ -476,6 +482,9 @@ def project_get_network(context, project_id):
|
||||
"""
|
||||
return IMPL.project_get_network(context, project_id)
|
||||
|
||||
def project_get_network_v6(context, project_id):
|
||||
return IMPL.project_get_network_v6(context, project_id)
|
||||
|
||||
|
||||
###################
|
||||
|
||||
|
@ -504,6 +504,16 @@ def fixed_ip_get_instance(context, address):
|
||||
fixed_ip_ref = fixed_ip_get_by_address(context, address)
|
||||
return fixed_ip_ref.instance
|
||||
|
||||
@require_context
|
||||
def fixed_ip_get_instance_v6(context, address):
|
||||
session = get_session()
|
||||
mac = utils.to_mac(address)
|
||||
|
||||
result = session.query(models.Instance
|
||||
).filter_by(mac_address=mac
|
||||
).first()
|
||||
return result
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def fixed_ip_get_network(context, address):
|
||||
@ -692,6 +702,15 @@ def instance_get_fixed_address(context, instance_id):
|
||||
return None
|
||||
return instance_ref.fixed_ip['address']
|
||||
|
||||
@require_context
|
||||
def instance_get_fixed_address_v6(context, instance_id):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
instance_ref = instance_get(context, instance_id, session=session)
|
||||
network_ref = project_get_network(context, context.project_id)
|
||||
prefix = network_ref.cidr_v6
|
||||
mac = instance_ref.mac_address
|
||||
return utils.to_global_ipv6(prefix, mac)
|
||||
|
||||
@require_context
|
||||
def instance_get_floating_address(context, instance_id):
|
||||
@ -1004,6 +1023,10 @@ def project_get_network(context, project_id):
|
||||
first()
|
||||
return rv
|
||||
|
||||
@require_context
|
||||
def project_get_network_v6(context, project_id):
|
||||
return project_get_network(context, project_id)
|
||||
|
||||
|
||||
###################
|
||||
|
||||
|
@ -389,6 +389,10 @@ class Network(BASE, NovaBase):
|
||||
|
||||
injected = Column(Boolean, default=False)
|
||||
cidr = Column(String(255), unique=True)
|
||||
cidr_v6 = Column(String(255), unique=True)
|
||||
|
||||
ra_server = Column(String(255))
|
||||
|
||||
netmask = Column(String(255))
|
||||
bridge = Column(String(255))
|
||||
gateway = Column(String(255))
|
||||
|
@ -53,6 +53,7 @@ flags.DEFINE_string('routing_source_ip', '127.0.0.1',
|
||||
flags.DEFINE_bool('use_nova_chains', False,
|
||||
'use the nova_ routing chains instead of default')
|
||||
|
||||
|
||||
DEFAULT_PORTS = [("tcp", 80), ("tcp", 22), ("udp", 1194), ("tcp", 443)]
|
||||
|
||||
|
||||
@ -75,6 +76,11 @@ def init_host():
|
||||
FLAGS.fixed_range)
|
||||
_confirm_rule("POSTROUTING", "-t nat -s %(range)s -d %(range)s -j ACCEPT" %
|
||||
{'range': FLAGS.fixed_range})
|
||||
if(FLAGS.use_ipv6):
|
||||
_execute('sudo bash -c ' +
|
||||
'"echo 1 > /proc/sys/net/ipv6/conf/all/forwarding"')
|
||||
_execute('sudo bash -c ' +
|
||||
'"echo 0 > /proc/sys/net/ipv6/conf/all/accept_ra"')
|
||||
|
||||
|
||||
def bind_floating_ip(floating_ip):
|
||||
@ -158,6 +164,10 @@ def ensure_bridge(bridge, interface, net_attrs=None):
|
||||
net_attrs['gateway'],
|
||||
net_attrs['broadcast'],
|
||||
net_attrs['netmask']))
|
||||
if(FLAGS.use_ipv6):
|
||||
_execute("sudo ifconfig %s add %s up" % \
|
||||
(bridge,
|
||||
net_attrs['cidr_v6']))
|
||||
else:
|
||||
_execute("sudo ifconfig %s up" % bridge)
|
||||
_confirm_rule("FORWARD", "--in-interface %s -j ACCEPT" % bridge)
|
||||
@ -213,6 +223,50 @@ def update_dhcp(context, network_id):
|
||||
_execute(command, addl_env=env)
|
||||
|
||||
|
||||
def update_ra(context, network_id):
|
||||
network_ref = db.network_get(context, network_id)
|
||||
|
||||
conffile = _ra_file(network_ref['bridge'], 'conf')
|
||||
with open(conffile, 'w') as f:
|
||||
conf_str = """
|
||||
interface %s
|
||||
{
|
||||
AdvSendAdvert on;
|
||||
MinRtrAdvInterval 3;
|
||||
MaxRtrAdvInterval 10;
|
||||
prefix %s
|
||||
{
|
||||
AdvOnLink on;
|
||||
AdvAutonomous on;
|
||||
};
|
||||
};
|
||||
""" % (network_ref['bridge'], network_ref['cidr_v6'])
|
||||
f.write(conf_str)
|
||||
|
||||
# Make sure dnsmasq can actually read it (it setuid()s to "nobody")
|
||||
os.chmod(conffile, 0644)
|
||||
|
||||
pid = _ra_pid_for(network_ref['bridge'])
|
||||
|
||||
# if dnsmasq is already running, then tell it to reload
|
||||
if pid:
|
||||
out, _err = _execute('cat /proc/%d/cmdline'
|
||||
% pid, check_exit_code=False)
|
||||
if conffile in out:
|
||||
try:
|
||||
_execute('sudo kill -HUP %d' % pid)
|
||||
return
|
||||
except Exception as exc: # pylint: disable-msg=W0703
|
||||
logging.debug("Hupping radvd threw %s", exc)
|
||||
else:
|
||||
logging.debug("Pid %d is stale, relaunching radvd", pid)
|
||||
command = _ra_cmd(network_ref)
|
||||
_execute(command)
|
||||
db.network_update(context, network_id,
|
||||
{"ra_server":
|
||||
utils.get_my_linklocal(network_ref['bridge'])})
|
||||
|
||||
|
||||
def _host_dhcp(fixed_ip_ref):
|
||||
"""Return a host string for an address"""
|
||||
instance_ref = fixed_ip_ref['instance']
|
||||
@ -268,6 +322,15 @@ def _dnsmasq_cmd(net):
|
||||
return ''.join(cmd)
|
||||
|
||||
|
||||
def _ra_cmd(net):
|
||||
"""Builds dnsmasq command"""
|
||||
cmd = ['sudo -E radvd',
|
||||
# ' -u nobody',
|
||||
' -C %s' % _ra_file(net['bridge'], 'conf'),
|
||||
' -p %s' % _ra_file(net['bridge'], 'pid')]
|
||||
return ''.join(cmd)
|
||||
|
||||
|
||||
def _stop_dnsmasq(network):
|
||||
"""Stops the dnsmasq instance for a given network"""
|
||||
pid = _dnsmasq_pid_for(network)
|
||||
@ -289,6 +352,16 @@ def _dhcp_file(bridge, kind):
|
||||
kind))
|
||||
|
||||
|
||||
def _ra_file(bridge, kind):
|
||||
"""Return path to a pid, leases or conf file for a bridge"""
|
||||
|
||||
if not os.path.exists(FLAGS.networks_path):
|
||||
os.makedirs(FLAGS.networks_path)
|
||||
return os.path.abspath("%s/nova-ra-%s.%s" % (FLAGS.networks_path,
|
||||
bridge,
|
||||
kind))
|
||||
|
||||
|
||||
def _dnsmasq_pid_for(bridge):
|
||||
"""Returns the pid for prior dnsmasq instance for a bridge
|
||||
|
||||
@ -302,3 +375,18 @@ def _dnsmasq_pid_for(bridge):
|
||||
if os.path.exists(pid_file):
|
||||
with open(pid_file, 'r') as f:
|
||||
return int(f.read())
|
||||
|
||||
|
||||
def _ra_pid_for(bridge):
|
||||
"""Returns the pid for prior dnsmasq instance for a bridge
|
||||
|
||||
Returns None if no pid file exists
|
||||
|
||||
If machine has rebooted pid might be incorrect (caller should check)
|
||||
"""
|
||||
|
||||
pid_file = _ra_file(bridge, 'pid')
|
||||
|
||||
if os.path.exists(pid_file):
|
||||
with open(pid_file, 'r') as f:
|
||||
return int(f.read())
|
||||
|
@ -80,6 +80,7 @@ flags.DEFINE_integer('network_size', 256,
|
||||
flags.DEFINE_string('floating_range', '4.4.4.0/24',
|
||||
'Floating IP address block')
|
||||
flags.DEFINE_string('fixed_range', '10.0.0.0/8', 'Fixed IP address block')
|
||||
flags.DEFINE_string('fixed_range_v6', 'fd00::/48', 'Fixed IPv6 address block')
|
||||
flags.DEFINE_integer('cnt_vpn_clients', 5,
|
||||
'Number of addresses reserved for vpn clients')
|
||||
flags.DEFINE_string('network_driver', 'nova.network.linux_net',
|
||||
@ -88,6 +89,8 @@ flags.DEFINE_bool('update_dhcp_on_disassociate', False,
|
||||
'Whether to update dhcp when fixed_ip is disassociated')
|
||||
flags.DEFINE_integer('fixed_ip_disassociate_timeout', 600,
|
||||
'Seconds after which a deallocated ip is disassociated')
|
||||
flags.DEFINE_bool('use_ipv6', True,
|
||||
'use the ipv6')
|
||||
|
||||
|
||||
class AddressAlreadyAllocated(exception.Error):
|
||||
@ -217,7 +220,7 @@ class NetworkManager(manager.Manager):
|
||||
"""Get the network for the current context."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_networks(self, context, num_networks, network_size,
|
||||
def create_networks(self, context, num_networks, network_size, cidr_v6,
|
||||
*args, **kwargs):
|
||||
"""Create networks based on parameters."""
|
||||
raise NotImplementedError()
|
||||
@ -307,9 +310,11 @@ class FlatManager(NetworkManager):
|
||||
pass
|
||||
|
||||
def create_networks(self, context, cidr, num_networks, network_size,
|
||||
*args, **kwargs):
|
||||
cidr_v6, *args, **kwargs):
|
||||
"""Create networks based on parameters."""
|
||||
fixed_net = IPy.IP(cidr)
|
||||
fixed_net_v6 = IPy.IP(cidr_v6)
|
||||
significant_bits_v6 = 64
|
||||
for index in range(num_networks):
|
||||
start = index * network_size
|
||||
significant_bits = 32 - int(math.log(network_size, 2))
|
||||
@ -322,7 +327,13 @@ class FlatManager(NetworkManager):
|
||||
net['gateway'] = str(project_net[1])
|
||||
net['broadcast'] = str(project_net.broadcast())
|
||||
net['dhcp_start'] = str(project_net[2])
|
||||
|
||||
if(FLAGS.use_ipv6):
|
||||
cidr_v6 = "%s/%s" % (fixed_net_v6[0], significant_bits_v6)
|
||||
net['cidr_v6'] = cidr_v6
|
||||
|
||||
network_ref = self.db.network_create_safe(context, net)
|
||||
|
||||
if network_ref:
|
||||
self._create_fixed_ips(context, network_ref['id'])
|
||||
|
||||
@ -466,12 +477,16 @@ class VlanManager(NetworkManager):
|
||||
pass
|
||||
|
||||
def create_networks(self, context, cidr, num_networks, network_size,
|
||||
vlan_start, vpn_start):
|
||||
vlan_start, vpn_start, cidr_v6):
|
||||
"""Create networks based on parameters."""
|
||||
fixed_net = IPy.IP(cidr)
|
||||
fixed_net_v6 = IPy.IP(cidr_v6)
|
||||
network_size_v6 = 1 << 64
|
||||
significant_bits_v6 = 64
|
||||
for index in range(num_networks):
|
||||
vlan = vlan_start + index
|
||||
start = index * network_size
|
||||
start_v6 = index * network_size_v6
|
||||
significant_bits = 32 - int(math.log(network_size, 2))
|
||||
cidr = "%s/%s" % (fixed_net[start], significant_bits)
|
||||
project_net = IPy.IP(cidr)
|
||||
@ -484,6 +499,13 @@ class VlanManager(NetworkManager):
|
||||
net['dhcp_start'] = str(project_net[3])
|
||||
net['vlan'] = vlan
|
||||
net['bridge'] = 'br%s' % vlan
|
||||
if(FLAGS.use_ipv6):
|
||||
cidr_v6 = "%s/%s" % (
|
||||
fixed_net_v6[start_v6],
|
||||
significant_bits_v6
|
||||
)
|
||||
net['cidr_v6'] = cidr_v6
|
||||
|
||||
# NOTE(vish): This makes ports unique accross the cloud, a more
|
||||
# robust solution would be to make them unique per ip
|
||||
net['vpn_public_port'] = vpn_start + index
|
||||
@ -506,6 +528,8 @@ class VlanManager(NetworkManager):
|
||||
network_ref['bridge'],
|
||||
network_ref)
|
||||
self.driver.update_dhcp(context, network_id)
|
||||
if(FLAGS.use_ipv6):
|
||||
self.driver.update_ra(context, network_id)
|
||||
|
||||
@property
|
||||
def _bottom_reserved_ips(self):
|
||||
|
@ -70,7 +70,8 @@ class TrialTestCase(unittest.TestCase):
|
||||
FLAGS.fixed_range,
|
||||
5, 16,
|
||||
FLAGS.vlan_start,
|
||||
FLAGS.vpn_start)
|
||||
FLAGS.vpn_start,
|
||||
FLAGS.fixed_range_v6)
|
||||
|
||||
# emulate some of the mox stuff, we can't use the metaclass
|
||||
# because it screws with our generators
|
||||
|
@ -24,6 +24,7 @@ import httplib
|
||||
import random
|
||||
import StringIO
|
||||
import webob
|
||||
import logging
|
||||
|
||||
from nova import context
|
||||
from nova import flags
|
||||
@ -265,6 +266,72 @@ class ApiEc2TestCase(test.TrialTestCase):
|
||||
|
||||
return
|
||||
|
||||
def test_authorize_revoke_security_group_cidr_v6(self):
|
||||
"""
|
||||
Test that we can add and remove CIDR based rules
|
||||
to a security group for IPv6
|
||||
"""
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
user = self.manager.create_user('fake', 'fake', 'fake')
|
||||
project = self.manager.create_project('fake', 'fake', 'fake')
|
||||
|
||||
# At the moment, you need both of these to actually be netadmin
|
||||
self.manager.add_role('fake', 'netadmin')
|
||||
project.add_role('fake', 'netadmin')
|
||||
|
||||
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd")
|
||||
for x in range(random.randint(4, 8)))
|
||||
|
||||
group = self.ec2.create_security_group(security_group_name,
|
||||
'test group')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
group.authorize('tcp', 80, 81, '::/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
# I don't bother checkng that we actually find it here,
|
||||
# because the create/delete unit test further up should
|
||||
# be good enough for that.
|
||||
for group in rv:
|
||||
if group.name == security_group_name:
|
||||
self.assertEquals(len(group.rules), 1)
|
||||
self.assertEquals(int(group.rules[0].from_port), 80)
|
||||
self.assertEquals(int(group.rules[0].to_port), 81)
|
||||
self.assertEquals(len(group.rules[0].grants), 1)
|
||||
self.assertEquals(str(group.rules[0].grants[0]), '::/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
group.revoke('tcp', 80, 81, '::/0')
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.ec2.delete_security_group(security_group_name)
|
||||
|
||||
self.expect_http()
|
||||
self.mox.ReplayAll()
|
||||
group.connection = self.ec2
|
||||
|
||||
rv = self.ec2.get_all_security_groups()
|
||||
|
||||
self.assertEqual(len(rv), 1)
|
||||
self.assertEqual(rv[0].name, 'default')
|
||||
|
||||
self.manager.delete_project(project)
|
||||
self.manager.delete_user(user)
|
||||
|
||||
return
|
||||
|
||||
def test_authorize_revoke_security_group_foreign_group(self):
|
||||
"""
|
||||
Test that we can grant and revoke another security group access
|
||||
|
@ -97,6 +97,27 @@ class NetworkTestCase(test.TrialTestCase):
|
||||
self.context.project_id = self.projects[project_num].id
|
||||
self.network.deallocate_fixed_ip(self.context, address)
|
||||
|
||||
def test_private_ipv6(self):
|
||||
"""Make sure ipv6 is OK"""
|
||||
if FLAGS.use_ipv6:
|
||||
instance_ref = self._create_instance(1)
|
||||
network_ref = db.project_get_network(
|
||||
self.context,
|
||||
self.context.project_id)
|
||||
address_v6 = db.instance_get_fixed_address_v6(
|
||||
self.context,
|
||||
instance_ref['id'])
|
||||
self.assertEqual(instance_ref['mac_address'],
|
||||
utils.to_mac(address_v6))
|
||||
instance_ref2 = db.fixed_ip_get_instance_v6(
|
||||
self.context,
|
||||
address_v6)
|
||||
self.assertEqual(instance_ref['id'], instance_ref2['id'])
|
||||
self.assertEqual(address_v6,
|
||||
utils.to_global_ipv6(
|
||||
network_ref['cidr_v6'],
|
||||
instance_ref['mac_address']))
|
||||
|
||||
def test_public_network_association(self):
|
||||
"""Makes sure that we can allocaate a public ip"""
|
||||
# TODO(vish): better way of adding floating ips
|
||||
|
@ -30,6 +30,8 @@ import subprocess
|
||||
import socket
|
||||
import sys
|
||||
from xml.sax import saxutils
|
||||
import re
|
||||
import netaddr
|
||||
|
||||
from twisted.internet.threads import deferToThread
|
||||
|
||||
@ -45,10 +47,14 @@ TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
||||
def import_class(import_str):
|
||||
"""Returns a class from a string including module and class"""
|
||||
mod_str, _sep, class_str = import_str.rpartition('.')
|
||||
logging.debug(import_str)
|
||||
try:
|
||||
__import__(mod_str)
|
||||
return getattr(sys.modules[mod_str], class_str)
|
||||
except (ImportError, ValueError, AttributeError):
|
||||
logging.debug(ImportError)
|
||||
logging.debug(ValueError)
|
||||
logging.debug(AttributeError)
|
||||
raise exception.NotFound('Class %s cannot be found' % class_str)
|
||||
|
||||
|
||||
@ -165,6 +171,39 @@ def get_my_ip():
|
||||
return "127.0.0.1"
|
||||
|
||||
|
||||
def get_my_linklocal(interface):
|
||||
if getattr(FLAGS, 'fake_tests', None):
|
||||
return 'fe00::'
|
||||
try:
|
||||
if_str = execute("ifconfig %s" % interface)
|
||||
condition = "\s+inet6\s+addr:\s+([0-9a-f:]+/\d+)\s+Scope:Link"
|
||||
links = [re.search(condition, x) for x in if_str[0].split('\n')]
|
||||
address = [w.group(1) for w in links if w is not None]
|
||||
if address[0] is not None:
|
||||
return address[0]
|
||||
else:
|
||||
return None
|
||||
except RuntimeError as ex:
|
||||
logging.warn("Couldn't get Link Local IP of %s :%s", interface, ex)
|
||||
return None
|
||||
|
||||
|
||||
def to_global_ipv6(prefix, mac):
|
||||
mac64 = netaddr.EUI(mac).eui64().words
|
||||
int_addr = int(''.join(['%02x' % i for i in mac64]), 16)
|
||||
mac64_addr = netaddr.IPAddress(int_addr)
|
||||
maskIP = netaddr.IPNetwork(prefix).ip
|
||||
return (mac64_addr ^ netaddr.IPAddress('::0200:0:0:0') | maskIP).format()
|
||||
|
||||
|
||||
def to_mac(ipv6_address):
|
||||
address = netaddr.IPAddress(ipv6_address)
|
||||
mask1 = netaddr.IPAddress("::ffff:ffff:ffff:ffff")
|
||||
mask2 = netaddr.IPAddress("::0200:0:0:0")
|
||||
mac64 = netaddr.EUI(int(address & mask1 ^ mask2)).words
|
||||
return ":".join(["%02x" % i for i in mac64[0:3] + mac64[5:8]])
|
||||
|
||||
|
||||
def isotime(at=None):
|
||||
if not at:
|
||||
at = datetime.datetime.utcnow()
|
||||
|
@ -23,6 +23,7 @@
|
||||
<filterref filter="nova-instance-%(name)s">
|
||||
<parameter name="IP" value="%(ip_address)s" />
|
||||
<parameter name="DHCPSERVER" value="%(dhcp_server)s" />
|
||||
<parameter name="RASERVER" value="%(ra_server)s" />
|
||||
</filterref>
|
||||
</interface>
|
||||
<serial type="file">
|
||||
|
@ -17,6 +17,7 @@
|
||||
<filterref filter="nova-instance-%(name)s">
|
||||
<parameter name="IP" value="%(ip_address)s" />
|
||||
<parameter name="DHCPSERVER" value="%(dhcp_server)s" />
|
||||
<parameter name="RASERVER" value="%(ra_server)s" />
|
||||
</filterref>
|
||||
</interface>
|
||||
<console type="file">
|
||||
|
@ -514,6 +514,8 @@ class LibvirtConnection(object):
|
||||
instance['id'])
|
||||
# Assume that the gateway also acts as the dhcp server.
|
||||
dhcp_server = network['gateway']
|
||||
#TODO ipv6
|
||||
ra_server = network['ra_server']
|
||||
xml_info = {'type': FLAGS.libvirt_type,
|
||||
'name': instance['name'],
|
||||
'basepath': os.path.join(FLAGS.instances_path,
|
||||
@ -523,11 +525,13 @@ class LibvirtConnection(object):
|
||||
'bridge_name': network['bridge'],
|
||||
'mac_address': instance['mac_address'],
|
||||
'ip_address': ip_address,
|
||||
'dhcp_server': dhcp_server}
|
||||
'dhcp_server': dhcp_server,
|
||||
'ra_server': ra_server}
|
||||
if rescue:
|
||||
libvirt_xml = self.rescue_xml % xml_info
|
||||
else:
|
||||
libvirt_xml = self.libvirt_xml % xml_info
|
||||
|
||||
logging.debug('instance %s: finished toXML method', instance['name'])
|
||||
|
||||
return libvirt_xml
|
||||
@ -701,6 +705,7 @@ class NWFilterFirewall(object):
|
||||
<filterref filter='no-arp-spoofing'/>
|
||||
<filterref filter='allow-dhcp-server'/>
|
||||
<filterref filter='nova-allow-dhcp-server'/>
|
||||
<filterref filter='nova-allow-ra-server'/>
|
||||
<filterref filter='nova-base-ipv4'/>
|
||||
<filterref filter='nova-base-ipv6'/>
|
||||
</filter>'''
|
||||
@ -722,6 +727,14 @@ class NWFilterFirewall(object):
|
||||
</rule>
|
||||
</filter>'''
|
||||
|
||||
nova_ra_filter = '''<filter name='nova-allow-ra-server' chain='root'>
|
||||
<uuid>d707fa71-4fb5-4b27-9ab7-ba5ca19c8804</uuid>
|
||||
<rule action='accept' direction='inout'
|
||||
priority='100'>
|
||||
<icmpv6 srcipaddr='$RASERVER'/>
|
||||
</rule>
|
||||
</filter>'''
|
||||
|
||||
def nova_base_ipv4_filter(self):
|
||||
retval = "<filter name='nova-base-ipv4' chain='ipv4'>"
|
||||
for protocol in ['tcp', 'udp', 'icmp']:
|
||||
@ -736,13 +749,13 @@ class NWFilterFirewall(object):
|
||||
|
||||
def nova_base_ipv6_filter(self):
|
||||
retval = "<filter name='nova-base-ipv6' chain='ipv6'>"
|
||||
for protocol in ['tcp', 'udp', 'icmp']:
|
||||
for protocol in ['tcp-ipv6', 'udp-ipv6', 'icmpv6']:
|
||||
for direction, action, priority in [('out', 'accept', 399),
|
||||
('inout', 'drop', 400)]:
|
||||
retval += """<rule action='%s' direction='%s' priority='%d'>
|
||||
<%s-ipv6 />
|
||||
<%s />
|
||||
</rule>""" % (action, direction,
|
||||
priority, protocol)
|
||||
priority, protocol)
|
||||
retval += '</filter>'
|
||||
return retval
|
||||
|
||||
@ -755,6 +768,15 @@ class NWFilterFirewall(object):
|
||||
retval += '</filter>'
|
||||
return retval
|
||||
|
||||
def nova_project_filter_v6(self, project, net, mask):
|
||||
retval = "<filter name='nova-project-%s-v6' chain='ipv6'>" % project
|
||||
for protocol in ['tcp-ipv6', 'udp-ipv6', 'icmpv6']:
|
||||
retval += """<rule action='accept' direction='inout' priority='200'>
|
||||
<%s srcipaddr='%s' srcipmask='%s' />
|
||||
</rule>""" % (protocol, net, mask)
|
||||
retval += '</filter>'
|
||||
return retval
|
||||
|
||||
def _define_filter(self, xml):
|
||||
if callable(xml):
|
||||
xml = xml()
|
||||
@ -766,6 +788,11 @@ class NWFilterFirewall(object):
|
||||
net = IPy.IP(cidr)
|
||||
return str(net.net()), str(net.netmask())
|
||||
|
||||
@staticmethod
|
||||
def _get_ip_version(cidr):
|
||||
net = IPy.IP(cidr)
|
||||
return int(net.version())
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def setup_nwfilters_for_instance(self, instance):
|
||||
"""
|
||||
@ -777,6 +804,7 @@ class NWFilterFirewall(object):
|
||||
yield self._define_filter(self.nova_base_ipv4_filter)
|
||||
yield self._define_filter(self.nova_base_ipv6_filter)
|
||||
yield self._define_filter(self.nova_dhcp_filter)
|
||||
yield self._define_filter(self.nova_ra_filter)
|
||||
yield self._define_filter(self.nova_base_filter)
|
||||
|
||||
nwfilter_xml = "<filter name='nova-instance-%s' chain='root'>\n" \
|
||||
@ -787,12 +815,22 @@ class NWFilterFirewall(object):
|
||||
network_ref = db.project_get_network(context.get_admin_context(),
|
||||
instance['project_id'])
|
||||
net, mask = self._get_net_and_mask(network_ref['cidr'])
|
||||
if(FLAGS.use_ipv6):
|
||||
net_v6, mask_v6 = self._get_net_and_mask(
|
||||
network_ref['cidr_v6'])
|
||||
project_filter = self.nova_project_filter(instance['project_id'],
|
||||
net, mask)
|
||||
yield self._define_filter(project_filter)
|
||||
|
||||
nwfilter_xml += " <filterref filter='nova-project-%s' />\n" % \
|
||||
instance['project_id']
|
||||
if(FLAGS.use_ipv6):
|
||||
project_filter_v6 = self.nova_project_filter_v6(
|
||||
instance['project_id'],
|
||||
net_v6, mask_v6)
|
||||
yield self._define_filter(project_filter_v6)
|
||||
nwfilter_xml += \
|
||||
" <filterref filter='nova-project-%s-v6' />\n" % \
|
||||
instance['project_id']
|
||||
|
||||
for security_group in instance.security_groups:
|
||||
yield self.ensure_security_group_filter(security_group['id'])
|
||||
@ -812,12 +850,21 @@ class NWFilterFirewall(object):
|
||||
security_group = db.security_group_get(context.get_admin_context(),
|
||||
security_group_id)
|
||||
rule_xml = ""
|
||||
version = 4
|
||||
v6protocol = {'tcp':'tcp-ipv6', 'udp':'udp-ipv6', 'icmp':'icmpv6'}
|
||||
for rule in security_group.rules:
|
||||
rule_xml += "<rule action='accept' direction='in' priority='300'>"
|
||||
if rule.cidr:
|
||||
version = self._get_ip_version(rule.cidr)
|
||||
net, mask = self._get_net_and_mask(rule.cidr)
|
||||
rule_xml += "<%s srcipaddr='%s' srcipmask='%s' " % \
|
||||
(rule.protocol, net, mask)
|
||||
if(FLAGS.use_ipv6 and version == 6):
|
||||
rule_xml += "<%s " % v6protocol[rule.protocol]
|
||||
rule_xml += "srcipaddr='%s' " % net
|
||||
rule_xml += "srcipmask='%s' " % mask
|
||||
else:
|
||||
rule_xml += "<%s " % rule.protocol
|
||||
rule_xml += "srcipaddr='%s' " % net
|
||||
rule_xml += "srcipmask='%s' " % mask
|
||||
if rule.protocol in ['tcp', 'udp']:
|
||||
rule_xml += "dstportstart='%s' dstportend='%s' " % \
|
||||
(rule.from_port, rule.to_port)
|
||||
@ -832,6 +879,9 @@ class NWFilterFirewall(object):
|
||||
|
||||
rule_xml += '/>\n'
|
||||
rule_xml += "</rule>\n"
|
||||
xml = "<filter name='nova-secgroup-%s' chain='ipv4'>%s</filter>" % \
|
||||
(security_group_id, rule_xml,)
|
||||
xml = "<filter name='nova-secgroup-%s' " % security_group_id
|
||||
if(FLAGS.use_ipv6):
|
||||
xml += "chain='root'>%s</filter>" % rule_xml
|
||||
else:
|
||||
xml += "chain='ipv4'>%s</filter>" % rule_xml
|
||||
return xml
|
||||
|
@ -36,7 +36,7 @@ flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
|
||||
# TODO(devamcar): Use random tempfile
|
||||
ZIP_FILENAME = '/tmp/nova-me-x509.zip'
|
||||
|
||||
TEST_PREFIX = 'test%s' % int(random.random()*1000000)
|
||||
TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
|
||||
TEST_USERNAME = '%suser' % TEST_PREFIX
|
||||
TEST_PROJECTNAME = '%sproject' % TEST_PREFIX
|
||||
|
||||
@ -89,4 +89,3 @@ class UserTests(AdminSmokeTestCase):
|
||||
if __name__ == "__main__":
|
||||
suites = {'user': unittest.makeSuite(UserTests)}
|
||||
sys.exit(base.run_tests(suites))
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
# under the License.
|
||||
|
||||
import boto
|
||||
import boto_v6
|
||||
import commands
|
||||
import httplib
|
||||
import os
|
||||
@ -69,6 +70,17 @@ class SmokeTestCase(unittest.TestCase):
|
||||
'test.')
|
||||
|
||||
parts = self.split_clc_url(clc_url)
|
||||
if FLAGS.use_ipv6:
|
||||
return boto_v6.connect_ec2(aws_access_key_id=access_key,
|
||||
aws_secret_access_key=secret_key,
|
||||
is_secure=parts['is_secure'],
|
||||
region=RegionInfo(None,
|
||||
'nova',
|
||||
parts['ip']),
|
||||
port=parts['port'],
|
||||
path='/services/Cloud',
|
||||
**kwargs)
|
||||
|
||||
return boto.connect_ec2(aws_access_key_id=access_key,
|
||||
aws_secret_access_key=secret_key,
|
||||
is_secure=parts['is_secure'],
|
||||
@ -115,7 +127,8 @@ class SmokeTestCase(unittest.TestCase):
|
||||
return True
|
||||
|
||||
def upload_image(self, bucket_name, image):
|
||||
cmd = 'euca-upload-bundle -b %s -m /tmp/%s.manifest.xml' % (bucket_name, image)
|
||||
cmd = 'euca-upload-bundle -b '
|
||||
cmd += '%s -m /tmp/%s.manifest.xml' % (bucket_name, image)
|
||||
status, output = commands.getstatusoutput(cmd)
|
||||
if status != 0:
|
||||
print '%s -> \n %s' % (cmd, output)
|
||||
@ -130,6 +143,7 @@ class SmokeTestCase(unittest.TestCase):
|
||||
raise Exception(output)
|
||||
return True
|
||||
|
||||
|
||||
def run_tests(suites):
|
||||
argv = FLAGS(sys.argv)
|
||||
|
||||
@ -151,4 +165,3 @@ def run_tests(suites):
|
||||
else:
|
||||
for suite in suites.itervalues():
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
|
||||
|
@ -33,6 +33,7 @@ DEFINE_bool = DEFINE_bool
|
||||
# __GLOBAL FLAGS ONLY__
|
||||
# Define any app-specific flags in their own files, docs at:
|
||||
# http://code.google.com/p/python-gflags/source/browse/trunk/gflags.py#39
|
||||
|
||||
DEFINE_string('region', 'nova', 'Region to use')
|
||||
DEFINE_string('test_image', 'ami-tiny', 'Image to use for launch tests')
|
||||
|
||||
DEFINE_string('use_ipv6', True, 'use the ipv6 or not')
|
||||
|
180
smoketests/public_network_smoketests.py
Normal file
180
smoketests/public_network_smoketests.py
Normal file
@ -0,0 +1,180 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# 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 commands
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from smoketests import flags
|
||||
from smoketests import base
|
||||
from smoketests import user_smoketests
|
||||
|
||||
#Note that this test should run from
|
||||
#public network (outside of private network segments)
|
||||
#Please set EC2_URL correctly
|
||||
#You should use admin account in this test
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
|
||||
TEST_BUCKET = '%s_bucket' % TEST_PREFIX
|
||||
TEST_KEY = '%s_key' % TEST_PREFIX
|
||||
TEST_KEY2 = '%s_key2' % TEST_PREFIX
|
||||
TEST_DATA = {}
|
||||
|
||||
|
||||
class InstanceTestsFromPublic(user_smoketests.UserSmokeTestCase):
|
||||
def test_001_can_create_keypair(self):
|
||||
key = self.create_key_pair(self.conn, TEST_KEY)
|
||||
self.assertEqual(key.name, TEST_KEY)
|
||||
|
||||
def test_002_security_group(self):
|
||||
security_group_name = "".join(random.choice("sdiuisudfsdcnpaqwertasd")
|
||||
for x in range(random.randint(4, 8)))
|
||||
group = self.conn.create_security_group(security_group_name,
|
||||
'test group')
|
||||
group.connection = self.conn
|
||||
group.authorize('tcp', 22, 22, '0.0.0.0/0')
|
||||
if FLAGS.use_ipv6:
|
||||
group.authorize('tcp', 22, 22, '::/0')
|
||||
|
||||
reservation = self.conn.run_instances(FLAGS.test_image,
|
||||
key_name=TEST_KEY,
|
||||
security_groups=[security_group_name],
|
||||
instance_type='m1.tiny')
|
||||
self.data['security_group_name'] = security_group_name
|
||||
self.data['group'] = group
|
||||
self.data['instance_id'] = reservation.instances[0].id
|
||||
|
||||
def test_003_instance_with_group_runs_within_60_seconds(self):
|
||||
reservations = self.conn.get_all_instances([self.data['instance_id']])
|
||||
instance = reservations[0].instances[0]
|
||||
# allow 60 seconds to exit pending with IP
|
||||
for x in xrange(60):
|
||||
instance.update()
|
||||
if instance.state == u'running':
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.fail('instance failed to start')
|
||||
ip = reservations[0].instances[0].private_dns_name
|
||||
self.failIf(ip == '0.0.0.0')
|
||||
self.data['private_ip'] = ip
|
||||
if FLAGS.use_ipv6:
|
||||
ipv6 = reservations[0].instances[0].dns_name_v6
|
||||
self.failIf(ipv6 is None)
|
||||
self.data['ip_v6'] = ipv6
|
||||
|
||||
def test_004_can_ssh_to_ipv6(self):
|
||||
if FLAGS.use_ipv6:
|
||||
for x in xrange(20):
|
||||
try:
|
||||
conn = self.connect_ssh(
|
||||
self.data['ip_v6'], TEST_KEY)
|
||||
conn.close()
|
||||
except Exception as ex:
|
||||
print ex
|
||||
time.sleep(1)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
self.fail('could not ssh to instance')
|
||||
|
||||
def test_012_can_create_instance_with_keypair(self):
|
||||
if 'instance_id' in self.data:
|
||||
self.conn.terminate_instances([self.data['instance_id']])
|
||||
reservation = self.conn.run_instances(FLAGS.test_image,
|
||||
key_name=TEST_KEY,
|
||||
instance_type='m1.tiny')
|
||||
self.assertEqual(len(reservation.instances), 1)
|
||||
self.data['instance_id'] = reservation.instances[0].id
|
||||
|
||||
def test_013_instance_runs_within_60_seconds(self):
|
||||
reservations = self.conn.get_all_instances([self.data['instance_id']])
|
||||
instance = reservations[0].instances[0]
|
||||
# allow 60 seconds to exit pending with IP
|
||||
for x in xrange(60):
|
||||
instance.update()
|
||||
if instance.state == u'running':
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.fail('instance failed to start')
|
||||
ip = reservations[0].instances[0].private_dns_name
|
||||
self.failIf(ip == '0.0.0.0')
|
||||
self.data['private_ip'] = ip
|
||||
if FLAGS.use_ipv6:
|
||||
ipv6 = reservations[0].instances[0].dns_name_v6
|
||||
self.failIf(ipv6 is None)
|
||||
self.data['ip_v6'] = ipv6
|
||||
|
||||
def test_014_can_not_ping_private_ip(self):
|
||||
for x in xrange(4):
|
||||
# ping waits for 1 second
|
||||
status, output = commands.getstatusoutput(
|
||||
'ping -c1 %s' % self.data['private_ip'])
|
||||
if status == 0:
|
||||
self.fail('can ping private ip from public network')
|
||||
if FLAGS.use_ipv6:
|
||||
status, output = commands.getstatusoutput(
|
||||
'ping6 -c1 %s' % self.data['ip_v6'])
|
||||
if status == 0:
|
||||
self.fail('can ping ipv6 from public network')
|
||||
else:
|
||||
pass
|
||||
|
||||
def test_015_can_not_ssh_to_private_ip(self):
|
||||
for x in xrange(1):
|
||||
try:
|
||||
conn = self.connect_ssh(self.data['private_ip'], TEST_KEY)
|
||||
conn.close()
|
||||
except Exception:
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.fail('can ssh for ipv4 address from public network')
|
||||
|
||||
if FLAGS.use_ipv6:
|
||||
for x in xrange(1):
|
||||
try:
|
||||
conn = self.connect_ssh(
|
||||
self.data['ip_v6'], TEST_KEY)
|
||||
conn.close()
|
||||
except Exception:
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.fail('can ssh for ipv6 address from public network')
|
||||
|
||||
def test_999_tearDown(self):
|
||||
self.delete_key_pair(self.conn, TEST_KEY)
|
||||
security_group_name = self.data['security_group_name']
|
||||
group = self.data['group']
|
||||
if group:
|
||||
group.revoke('tcp', 22, 22, '0.0.0.0/0')
|
||||
if FLAGS.use_ipv6:
|
||||
group.revoke('tcp', 22, 22, '::/0')
|
||||
self.conn.delete_security_group(security_group_name)
|
||||
if 'instance_id' in self.data:
|
||||
self.conn.terminate_instances([self.data['instance_id']])
|
||||
|
||||
if __name__ == "__main__":
|
||||
suites = {'instance': unittest.makeSuite(InstanceTestsFromPublic)}
|
||||
sys.exit(base.run_tests(suites))
|
@ -37,7 +37,7 @@ flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz',
|
||||
flags.DEFINE_string('bundle_image', 'openwrt-x86-ext2.image',
|
||||
'Local image file to use for bundling tests')
|
||||
|
||||
TEST_PREFIX = 'test%s' % int (random.random()*1000000)
|
||||
TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
|
||||
TEST_BUCKET = '%s_bucket' % TEST_PREFIX
|
||||
TEST_KEY = '%s_key' % TEST_PREFIX
|
||||
TEST_DATA = {}
|
||||
@ -71,7 +71,7 @@ class ImageTests(UserSmokeTestCase):
|
||||
|
||||
def test_006_can_register_kernel(self):
|
||||
kernel_id = self.conn.register_image('%s/%s.manifest.xml' %
|
||||
(TEST_BUCKET, FLAGS.bundle_kernel))
|
||||
(TEST_BUCKET, FLAGS.bundle_kernel))
|
||||
self.assert_(kernel_id is not None)
|
||||
self.data['kernel_id'] = kernel_id
|
||||
|
||||
@ -83,7 +83,7 @@ class ImageTests(UserSmokeTestCase):
|
||||
time.sleep(1)
|
||||
else:
|
||||
print image.state
|
||||
self.assert_(False) # wasn't available within 10 seconds
|
||||
self.assert_(False) # wasn't available within 10 seconds
|
||||
self.assert_(image.type == 'machine')
|
||||
|
||||
for i in xrange(10):
|
||||
@ -92,7 +92,7 @@ class ImageTests(UserSmokeTestCase):
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.assert_(False) # wasn't available within 10 seconds
|
||||
self.assert_(False) # wasn't available within 10 seconds
|
||||
self.assert_(kernel.type == 'kernel')
|
||||
|
||||
def test_008_can_describe_image_attribute(self):
|
||||
@ -137,20 +137,23 @@ class InstanceTests(UserSmokeTestCase):
|
||||
self.data['instance_id'] = reservation.instances[0].id
|
||||
|
||||
def test_003_instance_runs_within_60_seconds(self):
|
||||
reservations = self.conn.get_all_instances([data['instance_id']])
|
||||
reservations = self.conn.get_all_instances([self.data['instance_id']])
|
||||
instance = reservations[0].instances[0]
|
||||
# allow 60 seconds to exit pending with IP
|
||||
for x in xrange(60):
|
||||
instance.update()
|
||||
if instance.state == u'running':
|
||||
break
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.fail('instance failed to start')
|
||||
ip = reservations[0].instances[0].private_dns_name
|
||||
self.failIf(ip == '0.0.0.0')
|
||||
self.data['private_ip'] = ip
|
||||
print self.data['private_ip']
|
||||
if FLAGS.use_ipv6:
|
||||
ipv6 = reservations[0].instances[0].dns_name_v6
|
||||
self.failIf(ipv6 is None)
|
||||
self.data['ip_v6'] = ipv6
|
||||
|
||||
def test_004_can_ping_private_ip(self):
|
||||
for x in xrange(120):
|
||||
@ -159,6 +162,11 @@ class InstanceTests(UserSmokeTestCase):
|
||||
'ping -c1 %s' % self.data['private_ip'])
|
||||
if status == 0:
|
||||
break
|
||||
if FLAGS.use_ipv6:
|
||||
status, output = commands.getstatusoutput(
|
||||
'ping6 -c1 %s' % self.data['ip_v6'])
|
||||
if status == 0:
|
||||
break
|
||||
else:
|
||||
self.fail('could not ping instance')
|
||||
|
||||
@ -174,6 +182,19 @@ class InstanceTests(UserSmokeTestCase):
|
||||
else:
|
||||
self.fail('could not ssh to instance')
|
||||
|
||||
if FLAGS.use_ipv6:
|
||||
for x in xrange(30):
|
||||
try:
|
||||
conn = self.connect_ssh(
|
||||
self.data['ip_v6'], TEST_KEY)
|
||||
conn.close()
|
||||
except Exception:
|
||||
time.sleep(1)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
self.fail('could not ssh to instance')
|
||||
|
||||
def test_006_can_allocate_elastic_ip(self):
|
||||
result = self.conn.allocate_address()
|
||||
self.assertTrue(hasattr(result, 'public_ip'))
|
||||
@ -206,8 +227,8 @@ class InstanceTests(UserSmokeTestCase):
|
||||
|
||||
def test_999_tearDown(self):
|
||||
self.delete_key_pair(self.conn, TEST_KEY)
|
||||
if self.data.has_key('instance_id'):
|
||||
self.conn.terminate_instances([data['instance_id']])
|
||||
if 'instance_id' in self.data:
|
||||
self.conn.terminate_instances([self.data['instance_id']])
|
||||
|
||||
|
||||
class VolumeTests(UserSmokeTestCase):
|
||||
|
Loading…
x
Reference in New Issue
Block a user