From f7beae47ca505443eb86ea1a4fba6b47c1658755 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 24 Feb 2011 17:07:59 -0800
Subject: IPV6 FlatManager changes
---
nova/db/sqlalchemy/api.py | 11 ++--
.../versions/007_add_ipv6_flatmanager.py | 75 ++++++++++++++++++++++
nova/db/sqlalchemy/models.py | 3 +
nova/network/manager.py | 35 +++++++++-
nova/virt/interfaces.template | 16 +++--
nova/virt/libvirt_conn.py | 27 +++++---
6 files changed, 149 insertions(+), 18 deletions(-)
create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index d8751bef4..9bc59de60 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -833,10 +833,13 @@ 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 = network_get_by_instance(context, instance_id)
- prefix = network_ref.cidr_v6
- mac = instance_ref.mac_address
- return utils.to_global_ipv6(prefix, mac)
+ if 'nova.network.manager.FlatManager' == FLAGS.network_manager:
+ return instance_ref.fixed_ip['addressv6']
+ else:
+ network_ref = network_get_by_instance(context, instance_id)
+ prefix = network_ref.cidr_v6
+ mac = instance_ref.mac_address
+ return utils.to_global_ipv6(prefix, mac)
@require_context
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
new file mode 100644
index 000000000..2951cbc0a
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -0,0 +1,75 @@
+# Copyright 2010 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.
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+
+# Table stub-definitions
+# Just for the ForeignKey and column creation to succeed, these are not the
+# actual definitions of instances or services.
+#
+networks = Table('networks', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+fixed_ips = Table('fixed_ips', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+#
+# New Tables
+#
+# None
+
+#
+# Tables to alter
+#
+# None
+
+#
+# Columns to add to existing tables
+#
+
+networks_gatewayv6 = Column(
+ 'gatewayv6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+networks_netmaskv6 = Column(
+ 'netmaskv6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+fixed_ips_addressv6 = Column(
+ 'addressv6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+
+ # Add columns to existing tables
+ networks.create_column(networks_gatewayv6)
+ networks.create_column(networks_netmaskv6)
+ fixed_ips.create_column(fixed_ips_addressv6)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 1882efeba..4fa4d443c 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -385,6 +385,8 @@ class Network(BASE, NovaBase):
ra_server = Column(String(255))
+ gatewayv6 = Column(String(255))
+ netmaskv6 = Column(String(255))
netmask = Column(String(255))
bridge = Column(String(255))
gateway = Column(String(255))
@@ -425,6 +427,7 @@ class FixedIp(BASE, NovaBase):
__tablename__ = 'fixed_ips'
id = Column(Integer, primary_key=True)
address = Column(String(255))
+ addressv6 = Column(String(255))
network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
network = relationship(Network, backref=backref('fixed_ips'))
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 12a0c5018..61b5dc07f 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -361,9 +361,11 @@ class FlatManager(NetworkManager):
fixed_net = IPy.IP(cidr)
fixed_net_v6 = IPy.IP(cidr_v6)
significant_bits_v6 = 64
+ network_size_v6 = 1 << 64
count = 1
for index in range(num_networks):
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)
@@ -382,14 +384,45 @@ class FlatManager(NetworkManager):
count += 1
if(FLAGS.use_ipv6):
- cidr_v6 = "%s/%s" % (fixed_net_v6[0], significant_bits_v6)
+ cidr_v6 = "%s/%s" % (fixed_net_v6[start_v6],
+ significant_bits_v6)
net['cidr_v6'] = cidr_v6
+ project_net_v6 = IPy.IP(cidr_v6)
+ net['gatewayv6'] = str(project_net_v6[1])
+ net['netmaskv6'] = str(project_net_v6.prefixlen())
network_ref = self.db.network_create_safe(context, net)
if network_ref:
self._create_fixed_ips(context, network_ref['id'])
+ def _create_fixed_ips(self, context, network_id):
+ """Create all fixed ips for network."""
+ network_ref = self.db.network_get(context, network_id)
+ # NOTE(vish): Should these be properties of the network as opposed
+ # to properties of the manager class?
+ bottom_reserved = self._bottom_reserved_ips
+ top_reserved = self._top_reserved_ips
+ project_net = IPy.IP(network_ref['cidr'])
+
+ if(FLAGS.use_ipv6):
+ project_net_v6 = IPy.IP(network_ref['cidr_v6'])
+
+ num_ips = len(project_net)
+ addressv6 = None
+ for index in range(num_ips):
+ address = str(project_net[index])
+ if(FLAGS.use_ipv6):
+ addressv6 = str(project_net_v6[index])
+ if index < bottom_reserved or num_ips - index < top_reserved:
+ reserved = True
+ else:
+ reserved = False
+ self.db.fixed_ip_create(context, {'network_id': network_id,
+ 'address': address,
+ 'addressv6': addressv6,
+ 'reserved': reserved})
+
def get_network_host(self, context):
"""Get the network host for the current context."""
network_ref = self.db.network_get_by_bridge(context,
diff --git a/nova/virt/interfaces.template b/nova/virt/interfaces.template
index 87b92b84a..1db745f9f 100644
--- a/nova/virt/interfaces.template
+++ b/nova/virt/interfaces.template
@@ -8,10 +8,16 @@ iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet static
- address %(address)s
- netmask %(netmask)s
- broadcast %(broadcast)s
- gateway %(gateway)s
- dns-nameservers %(dns)s
+ address ${address}
+ netmask ${netmask}
+ broadcast ${broadcast}
+ gateway ${gateway}
+ dns-nameservers ${dns}
+#if $use_ipv6
+iface eth0 inet6 static
+ address ${addressv6}
+ netmask ${netmaskv6}
+ gateway ${gatewayv6}
+#end if
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 4e0fd106f..b7712f76e 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -146,6 +146,7 @@ class LibvirtConnection(object):
self.libvirt_uri = self.get_uri()
self.libvirt_xml = open(FLAGS.libvirt_xml_template).read()
+ self.interfaces_xml = open(FLAGS.injected_network_template).read()
self._wrapped_conn = None
self.read_only = read_only
@@ -628,17 +629,27 @@ class LibvirtConnection(object):
inst['id'])
if network_ref['injected']:
admin_context = context.get_admin_context()
- address = db.instance_get_fixed_address(admin_context, inst['id'])
+ address = db.instance_get_fixed_address(admin_context,
+ inst['id'])
+ addressv6 = db.instance_get_fixed_address_v6(admin_context,
+ inst['id'])
ra_server = network_ref['ra_server']
if not ra_server:
ra_server = "fd00::"
- with open(FLAGS.injected_network_template) as f:
- net = f.read() % {'address': address,
- 'netmask': network_ref['netmask'],
- 'gateway': network_ref['gateway'],
- 'broadcast': network_ref['broadcast'],
- 'dns': network_ref['dns'],
- 'ra_server': ra_server}
+
+ interfaces_info = {'address': address,
+ 'netmask': network_ref['netmask'],
+ 'gateway': network_ref['gateway'],
+ 'broadcast': network_ref['broadcast'],
+ 'dns': network_ref['dns'],
+ 'ra_server': ra_server,
+ 'addressv6': addressv6,
+ 'gatewayv6': network_ref['gatewayv6'],
+ 'netmaskv6': network_ref['netmaskv6'],
+ 'use_ipv6': FLAGS.use_ipv6}
+
+ net = str(Template(self.interfaces_xml,
+ searchList=[interfaces_info]))
if key or net:
inst_name = inst['name']
img_id = inst.image_id
--
cgit
From 20e9df05acdb89382023af1ac98cf040c827e18d Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 25 Feb 2011 14:49:33 -0800
Subject: DescribeInstances modified to return ipv6 fixed ip address in case of
flatmanager
---
nova/api/ec2/cloud.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 7458d307a..15799670c 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -701,9 +701,13 @@ class CloudController(object):
fixed = instance['fixed_ip']
floating_addr = fixed['floating_ips'][0]['address']
if instance['fixed_ip']['network'] and 'use_v6' in kwargs:
- i['dnsNameV6'] = utils.to_global_ipv6(
- instance['fixed_ip']['network']['cidr_v6'],
- instance['mac_address'])
+ if FLAGS.network_manager == \
+ 'nova.network.manager.FlatManager':
+ i['dnsNameV6'] = instance['fixed_ip']['addressv6']
+ else:
+ i['dnsNameV6'] = utils.to_global_ipv6(
+ instance['fixed_ip']['network']['cidr_v6'],
+ instance['mac_address'])
i['privateDnsName'] = fixed_addr
i['publicDnsName'] = floating_addr
--
cgit
From df0a4d66f7059db94e1de365fed8b8d244e16534 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Tue, 1 Mar 2011 17:12:47 -0800
Subject: Changed ra_server to gateway_v6 and removed addressv6 column from
fixed_ips db table
---
nova/api/ec2/cloud.py | 4 ---
nova/db/sqlalchemy/api.py | 11 +++---
.../versions/007_add_ipv6_flatmanager.py | 24 ++++---------
nova/db/sqlalchemy/models.py | 5 ++-
nova/network/linux_net.py | 2 +-
nova/network/manager.py | 37 +++++---------------
nova/virt/interfaces.template | 6 ++--
nova/virt/libvirt.xml.template | 4 +--
nova/virt/libvirt_conn.py | 40 +++++++++++-----------
9 files changed, 47 insertions(+), 86 deletions(-)
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 15799670c..b3779a4da 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -701,10 +701,6 @@ class CloudController(object):
fixed = instance['fixed_ip']
floating_addr = fixed['floating_ips'][0]['address']
if instance['fixed_ip']['network'] and 'use_v6' in kwargs:
- if FLAGS.network_manager == \
- 'nova.network.manager.FlatManager':
- i['dnsNameV6'] = instance['fixed_ip']['addressv6']
- else:
i['dnsNameV6'] = utils.to_global_ipv6(
instance['fixed_ip']['network']['cidr_v6'],
instance['mac_address'])
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 9bc59de60..d8751bef4 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -833,13 +833,10 @@ def instance_get_fixed_address_v6(context, instance_id):
session = get_session()
with session.begin():
instance_ref = instance_get(context, instance_id, session=session)
- if 'nova.network.manager.FlatManager' == FLAGS.network_manager:
- return instance_ref.fixed_ip['addressv6']
- else:
- network_ref = network_get_by_instance(context, instance_id)
- prefix = network_ref.cidr_v6
- mac = instance_ref.mac_address
- return utils.to_global_ipv6(prefix, mac)
+ network_ref = network_get_by_instance(context, instance_id)
+ prefix = network_ref.cidr_v6
+ mac = instance_ref.mac_address
+ return utils.to_global_ipv6(prefix, mac)
@require_context
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index 2951cbc0a..e09f46652 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -30,10 +30,6 @@ networks = Table('networks', meta,
Column('id', Integer(), primary_key=True, nullable=False),
)
-fixed_ips = Table('fixed_ips', meta,
- Column('id', Integer(), primary_key=True, nullable=False),
- )
-
#
# New Tables
#
@@ -42,24 +38,19 @@ fixed_ips = Table('fixed_ips', meta,
#
# Tables to alter
#
-# None
+
#
# Columns to add to existing tables
#
-networks_gatewayv6 = Column(
- 'gatewayv6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
-
-networks_netmaskv6 = Column(
- 'netmaskv6',
+networks_gateway_v6 = Column(
+ 'gateway_v6',
String(length=255, convert_unicode=False, assert_unicode=None,
unicode_error=None, _warn_on_bytestring=False))
-fixed_ips_addressv6 = Column(
- 'addressv6',
+networks_netmask_v6 = Column(
+ 'netmask_v6',
String(length=255, convert_unicode=False, assert_unicode=None,
unicode_error=None, _warn_on_bytestring=False))
@@ -70,6 +61,5 @@ def upgrade(migrate_engine):
meta.bind = migrate_engine
# Add columns to existing tables
- networks.create_column(networks_gatewayv6)
- networks.create_column(networks_netmaskv6)
- fixed_ips.create_column(fixed_ips_addressv6)
+ networks.create_column(networks_gateway_v6)
+ networks.create_column(networks_netmask_v6)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 4fa4d443c..f235054d2 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -385,8 +385,8 @@ class Network(BASE, NovaBase):
ra_server = Column(String(255))
- gatewayv6 = Column(String(255))
- netmaskv6 = Column(String(255))
+ gateway_v6 = Column(String(255))
+ netmask_v6 = Column(String(255))
netmask = Column(String(255))
bridge = Column(String(255))
gateway = Column(String(255))
@@ -427,7 +427,6 @@ class FixedIp(BASE, NovaBase):
__tablename__ = 'fixed_ips'
id = Column(Integer, primary_key=True)
address = Column(String(255))
- addressv6 = Column(String(255))
network_id = Column(Integer, ForeignKey('networks.id'), nullable=True)
network = relationship(Network, backref=backref('fixed_ips'))
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 535ce87bc..e375568f1 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -361,7 +361,7 @@ interface %s
command = _ra_cmd(network_ref)
_execute(command)
db.network_update(context, network_id,
- {"ra_server":
+ {"gateway_v6":
utils.get_my_linklocal(network_ref['bridge'])})
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 61b5dc07f..bdeeae293 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -388,41 +388,14 @@ class FlatManager(NetworkManager):
significant_bits_v6)
net['cidr_v6'] = cidr_v6
project_net_v6 = IPy.IP(cidr_v6)
- net['gatewayv6'] = str(project_net_v6[1])
- net['netmaskv6'] = str(project_net_v6.prefixlen())
+ net['gateway_v6'] = str(project_net_v6[1])
+ net['netmask_v6'] = str(project_net_v6.prefixlen())
network_ref = self.db.network_create_safe(context, net)
if network_ref:
self._create_fixed_ips(context, network_ref['id'])
- def _create_fixed_ips(self, context, network_id):
- """Create all fixed ips for network."""
- network_ref = self.db.network_get(context, network_id)
- # NOTE(vish): Should these be properties of the network as opposed
- # to properties of the manager class?
- bottom_reserved = self._bottom_reserved_ips
- top_reserved = self._top_reserved_ips
- project_net = IPy.IP(network_ref['cidr'])
-
- if(FLAGS.use_ipv6):
- project_net_v6 = IPy.IP(network_ref['cidr_v6'])
-
- num_ips = len(project_net)
- addressv6 = None
- for index in range(num_ips):
- address = str(project_net[index])
- if(FLAGS.use_ipv6):
- addressv6 = str(project_net_v6[index])
- if index < bottom_reserved or num_ips - index < top_reserved:
- reserved = True
- else:
- reserved = False
- self.db.fixed_ip_create(context, {'network_id': network_id,
- 'address': address,
- 'addressv6': addressv6,
- 'reserved': reserved})
-
def get_network_host(self, context):
"""Get the network host for the current context."""
network_ref = self.db.network_get_by_bridge(context,
@@ -448,6 +421,12 @@ class FlatManager(NetworkManager):
net = {}
net['injected'] = FLAGS.flat_injected
net['dns'] = FLAGS.flat_network_dns
+
+ if not FLAGS.fake_network:
+ if(FLAGS.use_ipv6):
+ net['gateway_v6'] = \
+ utils.get_my_linklocal(FLAGS.flat_network_bridge)
+
self.db.network_update(context, network_id, net)
def allocate_floating_ip(self, context, project_id):
diff --git a/nova/virt/interfaces.template b/nova/virt/interfaces.template
index 1db745f9f..3b34e54f4 100644
--- a/nova/virt/interfaces.template
+++ b/nova/virt/interfaces.template
@@ -16,8 +16,8 @@ iface eth0 inet static
#if $use_ipv6
iface eth0 inet6 static
- address ${addressv6}
- netmask ${netmaskv6}
- gateway ${gatewayv6}
+ address ${address_v6}
+ netmask ${netmask_v6}
+ gateway ${gateway_v6}
#end if
diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template
index 88bfbc668..ef2d2cd6b 100644
--- a/nova/virt/libvirt.xml.template
+++ b/nova/virt/libvirt.xml.template
@@ -79,8 +79,8 @@
#if $getVar('extra_params', False)
${extra_params}
#end if
-#if $getVar('ra_server', False)
-
+#if $getVar('gateway_v6', False)
+
#end if
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index b7712f76e..38fa2338e 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -631,21 +631,21 @@ class LibvirtConnection(object):
admin_context = context.get_admin_context()
address = db.instance_get_fixed_address(admin_context,
inst['id'])
- addressv6 = db.instance_get_fixed_address_v6(admin_context,
+ address_v6 = db.instance_get_fixed_address_v6(admin_context,
inst['id'])
- ra_server = network_ref['ra_server']
- if not ra_server:
- ra_server = "fd00::"
+ gateway_v6 = network_ref['gateway_v6']
+ if not gateway_v6:
+ gateway_v6 = "fd00::"
interfaces_info = {'address': address,
'netmask': network_ref['netmask'],
'gateway': network_ref['gateway'],
'broadcast': network_ref['broadcast'],
'dns': network_ref['dns'],
- 'ra_server': ra_server,
- 'addressv6': addressv6,
- 'gatewayv6': network_ref['gatewayv6'],
- 'netmaskv6': network_ref['netmaskv6'],
+ 'gateway_v6': gateway_v6,
+ 'address_v6': address_v6,
+ 'gateway_v6': network_ref['gateway_v6'],
+ 'netmask_v6': network_ref['netmask_v6'],
'use_ipv6': FLAGS.use_ipv6}
net = str(Template(self.interfaces_xml,
@@ -683,7 +683,7 @@ class LibvirtConnection(object):
instance['id'])
# Assume that the gateway also acts as the dhcp server.
dhcp_server = network['gateway']
- ra_server = network['ra_server']
+ gateway_v6 = network['gateway_v6']
if FLAGS.allow_project_net_traffic:
if FLAGS.use_ipv6:
@@ -728,8 +728,8 @@ class LibvirtConnection(object):
'local': instance_type['local_gb'],
'driver_type': driver_type}
- if ra_server:
- xml_info['ra_server'] = ra_server + "/128"
+ if gateway_v6:
+ xml_info['gateway_v6'] = gateway_v6 + "/128"
if not rescue:
if instance['kernel_id']:
xml_info['kernel'] = xml_info['basepath'] + "/kernel"
@@ -921,10 +921,10 @@ class FirewallDriver(object):
"""
raise NotImplementedError()
- def _ra_server_for_instance(self, instance):
+ def _gateway_v6_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
- return network['ra_server']
+ return network['gateway_v6']
class NWFilterFirewall(FirewallDriver):
@@ -1140,8 +1140,8 @@ class NWFilterFirewall(FirewallDriver):
'nova-base-ipv6',
'nova-allow-dhcp-server']
if FLAGS.use_ipv6:
- ra_server = self._ra_server_for_instance(instance)
- if ra_server:
+ gateway_v6 = self._gateway_v6_for_instance(instance)
+ if gateway_v6:
instance_secgroup_filter_children += ['nova-allow-ra-server']
ctxt = context.get_admin_context()
@@ -1328,10 +1328,10 @@ class IptablesFirewallDriver(FirewallDriver):
our_rules += ['-A %s -s %s -j ACCEPT' % (chain_name, cidr)]
elif(ip_version == 6):
# Allow RA responses
- ra_server = self._ra_server_for_instance(instance)
- if ra_server:
+ gateway_v6 = self._gateway_v6_for_instance(instance)
+ if gateway_v6:
our_rules += ['-A %s -s %s -p icmpv6 -j ACCEPT' %
- (chain_name, ra_server + "/128")]
+ (chain_name, gateway_v6 + "/128")]
#Allow project network traffic
if (FLAGS.allow_project_net_traffic):
cidrv6 = self._project_cidrv6_for_instance(instance)
@@ -1427,10 +1427,10 @@ class IptablesFirewallDriver(FirewallDriver):
instance['id'])
return network['gateway']
- def _ra_server_for_instance(self, instance):
+ def _gateway_v6_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
instance['id'])
- return network['ra_server']
+ return network['gateway_v6']
def _project_cidr_for_instance(self, instance):
network = db.network_get_by_instance(context.get_admin_context(),
--
cgit
From 0a9ba675c88ae0b2a18f47524d24075409261658 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 3 Mar 2011 15:39:23 -0800
Subject: altered ra_server name to gateway_v6
---
.../versions/007_add_ipv6_flatmanager.py | 14 ++--
.../versions/007_add_ipv6_to_fixed_ips.py | 90 ----------------------
2 files changed, 6 insertions(+), 98 deletions(-)
delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index e09f46652..937712970 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -28,7 +28,10 @@ meta = MetaData()
#
networks = Table('networks', meta,
Column('id', Integer(), primary_key=True, nullable=False),
- )
+ Column('ra_server', String(length=255, convert_unicode=False,
+ assert_unicode=None, unicode_error=None,
+ _warn_on_bytestring=False))
+ )
#
# New Tables
@@ -43,12 +46,6 @@ networks = Table('networks', meta,
#
# Columns to add to existing tables
#
-
-networks_gateway_v6 = Column(
- 'gateway_v6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
-
networks_netmask_v6 = Column(
'netmask_v6',
String(length=255, convert_unicode=False, assert_unicode=None,
@@ -60,6 +57,7 @@ def upgrade(migrate_engine):
# bind migrate_engine to your metadata
meta.bind = migrate_engine
+ # Alter column name
+ networks.c.ra_server.alter(name='gateway_v6')
# Add columns to existing tables
- networks.create_column(networks_gateway_v6)
networks.create_column(networks_netmask_v6)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py
deleted file mode 100644
index 427934d53..000000000
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_to_fixed_ips.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# 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.
-
-from sqlalchemy import *
-from migrate import *
-
-from nova import log as logging
-
-
-meta = MetaData()
-
-
-# Table stub-definitions
-# Just for the ForeignKey and column creation to succeed, these are not the
-# actual definitions of instances or services.
-#
-fixed_ips = Table(
- "fixed_ips",
- meta,
- Column(
- "id",
- Integer(),
- primary_key=True,
- nullable=False))
-
-#
-# New Tables
-#
-# None
-
-#
-# Tables to alter
-#
-# None
-
-#
-# Columns to add to existing tables
-#
-
-fixed_ips_addressV6 = Column(
- "addressV6",
- String(
- length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False))
-
-
-fixed_ips_netmaskV6 = Column(
- "netmaskV6",
- String(
- length=3,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False))
-
-
-fixed_ips_gatewayV6 = Column(
- "gatewayV6",
- String(
- length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False))
-
-
-def upgrade(migrate_engine):
- # Upgrade operations go here. Don't create your own engine;
- # bind migrate_engine to your metadata
- meta.bind = migrate_engine
-
- # Add columns to existing tables
- fixed_ips.create_column(fixed_ips_addressV6)
- fixed_ips.create_column(fixed_ips_netmaskV6)
- fixed_ips.create_column(fixed_ips_gatewayV6)
--
cgit
From 35be7d39866f6ac1017dd94d33d9c01f47a6bc74 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 3 Mar 2011 15:44:01 -0800
Subject: Removed properties added to fixed_ips by xs-ipv6 BP
---
nova/db/sqlalchemy/models.py | 3 ---
nova/network/manager.py | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 4c94cd3db..7b4683427 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -458,9 +458,6 @@ class FixedIp(BASE, NovaBase):
allocated = Column(Boolean, default=False)
leased = Column(Boolean, default=False)
reserved = Column(Boolean, default=False)
- addressV6 = Column(String(255))
- netmaskV6 = Column(String(3))
- gatewayV6 = Column(String(255))
class User(BASE, NovaBase):
diff --git a/nova/network/manager.py b/nova/network/manager.py
index fb6e16772..686ab9732 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -167,7 +167,7 @@ class NetworkManager(manager.Manager):
# with a network, or a cluster of computes with a network
# and use that network here with a method like
# network_get_by_compute_host
- network_ref = self.db.network_get_by_bridge(context,
+ network_ref = self.db.network_get_by_bridge(context.elevated(),
FLAGS.flat_network_bridge)
address = self.db.fixed_ip_associate_pool(context.elevated(),
network_ref['id'],
--
cgit
From aa09f87060c1d1885b7a557ff26a3c421ad42df8 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 3 Mar 2011 17:31:37 -0800
Subject: remove ra_server from model and fix migration issue while running
unit tests
---
.../versions/007_add_ipv6_flatmanager.py | 60 +++++++++++++++++++---
nova/db/sqlalchemy/models.py | 2 -
2 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index 937712970..d14f52af1 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+from lib2to3.fixer_util import String
from sqlalchemy import *
from migrate import *
@@ -27,12 +28,59 @@ meta = MetaData()
# actual definitions of instances or services.
#
networks = Table('networks', meta,
+ Column('created_at', DateTime(timezone=False)),
+ Column('updated_at', DateTime(timezone=False)),
+ Column('deleted_at', DateTime(timezone=False)),
+ Column('deleted', Boolean(create_constraint=True, name=None)),
Column('id', Integer(), primary_key=True, nullable=False),
- Column('ra_server', String(length=255, convert_unicode=False,
- assert_unicode=None, unicode_error=None,
- _warn_on_bytestring=False))
- )
-
+ Column('injected', Boolean(create_constraint=True, name=None)),
+ Column('cidr',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('netmask',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('bridge',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('gateway',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('broadcast',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dns',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vlan', Integer()),
+ Column('vpn_public_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vpn_public_port', Integer()),
+ Column('vpn_private_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dhcp_start',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('project_id',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('host',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('cidr_v6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column(
+ 'ra_server',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column(
+ 'label',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+ )
#
# New Tables
#
@@ -59,5 +107,5 @@ def upgrade(migrate_engine):
# Alter column name
networks.c.ra_server.alter(name='gateway_v6')
- # Add columns to existing tables
+ # Add new column to existing table
networks.create_column(networks_netmask_v6)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 7b4683427..14ff46647 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -402,8 +402,6 @@ class Network(BASE, NovaBase):
cidr = Column(String(255), unique=True)
cidr_v6 = Column(String(255), unique=True)
- ra_server = Column(String(255))
-
gateway_v6 = Column(String(255))
netmask_v6 = Column(String(255))
netmask = Column(String(255))
--
cgit
From 1831f31af0ac21ded3535f15777bd5147c615c34 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 4 Mar 2011 11:52:18 -0800
Subject: added flatmanager unit testcases and renamed test_network.py to
test_vlan_network.py
---
nova/tests/test_flat_network.py | 276 +++++++++++++++++++++++++++++
nova/tests/test_network.py | 369 ---------------------------------------
nova/tests/test_vlan_network.py | 373 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 649 insertions(+), 369 deletions(-)
create mode 100644 nova/tests/test_flat_network.py
delete mode 100644 nova/tests/test_network.py
create mode 100644 nova/tests/test_vlan_network.py
diff --git a/nova/tests/test_flat_network.py b/nova/tests/test_flat_network.py
new file mode 100644
index 000000000..91a49920d
--- /dev/null
+++ b/nova/tests/test_flat_network.py
@@ -0,0 +1,276 @@
+# 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.
+"""
+Unit Tests for network code
+"""
+import IPy
+import os
+import unittest
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class FlatNetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(FlatNetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(5):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(FlatNetworkTestCase, self).tearDown()
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ 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(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_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']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_public_network_association(self):
+ """Makes sure that we can allocate a public ip"""
+ # TODO(vish): better way of adding floating ips
+
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ pubnet = IPy.IP(flags.FLAGS.floating_range)
+ address = str(pubnet[0])
+ try:
+ db.floating_ip_get_by_address(context.get_admin_context(), address)
+ except exception.NotFound:
+ db.floating_ip_create(context.get_admin_context(),
+ {'address': address,
+ 'host': FLAGS.host})
+
+ self.assertRaises(NotImplementedError,
+ self.network.allocate_floating_ip,
+ self.context, self.projects[0].id)
+
+ fix_addr = self._create_address(0)
+ float_addr = address
+ self.assertRaises(NotImplementedError,
+ self.network.associate_floating_ip,
+ self.context, float_addr, fix_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.disassociate_floating_ip,
+ self.context, float_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.deallocate_floating_ip,
+ self.context, float_addr)
+
+ self.network.deallocate_fixed_ip(self.context, fix_addr)
+ db.floating_ip_destroy(context.get_admin_context(), float_addr)
+
+ def test_allocate_deallocate_fixed_ip(self):
+ """Makes sure that we can allocate and deallocate a fixed ip"""
+ address = self._create_address(0)
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self._deallocate_address(0, address)
+
+ # check if the fixed ip address is really deallocated
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ def test_side_effects(self):
+ """Ensures allocating and releasing has no side effects"""
+ address = self._create_address(0)
+ address2 = self._create_address(1, self.instance2_id)
+
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+
+ self._deallocate_address(0, address)
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ # First address release shouldn't affect the second
+ self.assertTrue(is_allocated_in_project(address2, self.projects[0].id))
+
+ self._deallocate_address(1, address2)
+ self.assertFalse(is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ def test_ips_are_reused(self):
+ """Makes sure that ip addresses that are deallocated get reused"""
+ address = self._create_address(0)
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ address2 = self._create_address(0)
+ self.assertEqual(address, address2)
+
+ self.network.deallocate_fixed_ip(self.context, address2)
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
+
+ def test_too_many_addresses(self):
+ """Test for a NoMoreAddresses exception when all fixed ips are used.
+ """
+ admin_context = context.get_admin_context()
+ network = db.project_get_network(admin_context, self.projects[0].id)
+ num_available_ips = db.network_count_available_ips(admin_context,
+ network['id'])
+ addresses = []
+ instance_ids = []
+ for i in range(num_available_ips):
+ instance_ref = self._create_instance(0)
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(0, instance_ref['id'])
+ addresses.append(address)
+
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, 0)
+ self.assertRaises(db.NoMoreAddresses,
+ self.network.allocate_fixed_ip,
+ self.context,
+ 'foo')
+
+ for i in range(num_available_ips):
+ self.network.deallocate_fixed_ip(self.context, addresses[i])
+ db.instance_destroy(context.get_admin_context(), instance_ids[i])
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, num_available_ips)
+
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
+ super(FlatNetworkTestCase, self).run(result)
+
+
+def is_allocated_in_project(address, project_id):
+ """Returns true if address is in specified project"""
+ #project_net = db.project_get_network(context.get_admin_context(),
+ # project_id)
+ project_net = db.network_get_by_bridge(context.get_admin_context(),
+ FLAGS.flat_network_bridge)
+ network = db.fixed_ip_get_network(context.get_admin_context(), address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../bin", script))
diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py
deleted file mode 100644
index ce1c77210..000000000
--- a/nova/tests/test_network.py
+++ /dev/null
@@ -1,369 +0,0 @@
-# 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.
-"""
-Unit Tests for network code
-"""
-import IPy
-import os
-
-from nova import context
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import test
-from nova import utils
-from nova.auth import manager
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-class NetworkTestCase(test.TestCase):
- """Test cases for network code"""
- def setUp(self):
- super(NetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(FLAGS.num_networks):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(NetworkTestCase, self).tearDown()
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- 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(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_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']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
- def test_public_network_association(self):
- """Makes sure that we can allocaate a public ip"""
- # TODO(vish): better way of adding floating ips
- self.context._project = self.projects[0]
- self.context.project_id = self.projects[0].id
- pubnet = IPy.IP(flags.FLAGS.floating_range)
- address = str(pubnet[0])
- try:
- db.floating_ip_get_by_address(context.get_admin_context(), address)
- except exception.NotFound:
- db.floating_ip_create(context.get_admin_context(),
- {'address': address,
- 'host': FLAGS.host})
- float_addr = self.network.allocate_floating_ip(self.context,
- self.projects[0].id)
- fix_addr = self._create_address(0)
- lease_ip(fix_addr)
- self.assertEqual(float_addr, str(pubnet[0]))
- self.network.associate_floating_ip(self.context, float_addr, fix_addr)
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, float_addr)
- self.network.disassociate_floating_ip(self.context, float_addr)
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, None)
- self.network.deallocate_floating_ip(self.context, float_addr)
- self.network.deallocate_fixed_ip(self.context, fix_addr)
- release_ip(fix_addr)
- db.floating_ip_destroy(context.get_admin_context(), float_addr)
-
- def test_allocate_deallocate_fixed_ip(self):
- """Makes sure that we can allocate and deallocate a fixed ip"""
- address = self._create_address(0)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- lease_ip(address)
- self._deallocate_address(0, address)
-
- # Doesn't go away until it's dhcp released
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
-
- release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
-
- def test_side_effects(self):
- """Ensures allocating and releasing has no side effects"""
- address = self._create_address(0)
- address2 = self._create_address(1, self.instance2_id)
-
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
- self.assertFalse(is_allocated_in_project(address, self.projects[1].id))
-
- # Addresses are allocated before they're issued
- lease_ip(address)
- lease_ip(address2)
-
- self._deallocate_address(0, address)
- release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
-
- # First address release shouldn't affect the second
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
-
- self._deallocate_address(1, address2)
- release_ip(address2)
- self.assertFalse(is_allocated_in_project(address2,
- self.projects[1].id))
-
- def test_subnet_edge(self):
- """Makes sure that private ips don't overlap"""
- first = self._create_address(0)
- lease_ip(first)
- instance_ids = []
- for i in range(1, FLAGS.num_networks):
- instance_ref = self._create_instance(i, mac=utils.generate_mac())
- instance_ids.append(instance_ref['id'])
- address = self._create_address(i, instance_ref['id'])
- instance_ref = self._create_instance(i, mac=utils.generate_mac())
- instance_ids.append(instance_ref['id'])
- address2 = self._create_address(i, instance_ref['id'])
- instance_ref = self._create_instance(i, mac=utils.generate_mac())
- instance_ids.append(instance_ref['id'])
- address3 = self._create_address(i, instance_ref['id'])
- lease_ip(address)
- lease_ip(address2)
- lease_ip(address3)
- self.context._project = self.projects[i]
- self.context.project_id = self.projects[i].id
- self.assertFalse(is_allocated_in_project(address,
- self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address2,
- self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address3,
- self.projects[0].id))
- self.network.deallocate_fixed_ip(self.context, address)
- self.network.deallocate_fixed_ip(self.context, address2)
- self.network.deallocate_fixed_ip(self.context, address3)
- release_ip(address)
- release_ip(address2)
- release_ip(address3)
- for instance_id in instance_ids:
- db.instance_destroy(context.get_admin_context(), instance_id)
- self.context._project = self.projects[0]
- self.context.project_id = self.projects[0].id
- self.network.deallocate_fixed_ip(self.context, first)
- self._deallocate_address(0, first)
- release_ip(first)
-
- def test_vpn_ip_and_port_looks_valid(self):
- """Ensure the vpn ip and port are reasonable"""
- self.assert_(self.projects[0].vpn_ip)
- self.assert_(self.projects[0].vpn_port >= FLAGS.vpn_start)
- self.assert_(self.projects[0].vpn_port <= FLAGS.vpn_start +
- FLAGS.num_networks)
-
- def test_too_many_networks(self):
- """Ensure error is raised if we run out of networks"""
- projects = []
- networks_left = (FLAGS.num_networks -
- db.network_count(context.get_admin_context()))
- for i in range(networks_left):
- project = self.manager.create_project('many%s' % i, self.user)
- projects.append(project)
- db.project_get_network(context.get_admin_context(), project.id)
- project = self.manager.create_project('last', self.user)
- projects.append(project)
- self.assertRaises(db.NoMoreNetworks,
- db.project_get_network,
- context.get_admin_context(),
- project.id)
- for project in projects:
- self.manager.delete_project(project)
-
- def test_ips_are_reused(self):
- """Makes sure that ip addresses that are deallocated get reused"""
- address = self._create_address(0)
- lease_ip(address)
- self.network.deallocate_fixed_ip(self.context, address)
- release_ip(address)
-
- address2 = self._create_address(0)
- self.assertEqual(address, address2)
- lease_ip(address)
- self.network.deallocate_fixed_ip(self.context, address2)
- release_ip(address)
-
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
-
- def test_too_many_addresses(self):
- """Test for a NoMoreAddresses exception when all fixed ips are used.
- """
- admin_context = context.get_admin_context()
- network = db.project_get_network(admin_context, self.projects[0].id)
- num_available_ips = db.network_count_available_ips(admin_context,
- network['id'])
- addresses = []
- instance_ids = []
- for i in range(num_available_ips):
- instance_ref = self._create_instance(0)
- instance_ids.append(instance_ref['id'])
- address = self._create_address(0, instance_ref['id'])
- addresses.append(address)
- lease_ip(address)
-
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, 0)
- self.assertRaises(db.NoMoreAddresses,
- self.network.allocate_fixed_ip,
- self.context,
- 'foo')
-
- for i in range(num_available_ips):
- self.network.deallocate_fixed_ip(self.context, addresses[i])
- release_ip(addresses[i])
- db.instance_destroy(context.get_admin_context(), instance_ids[i])
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, num_available_ips)
-
-
-def is_allocated_in_project(address, project_id):
- """Returns true if address is in specified project"""
- project_net = db.project_get_network(context.get_admin_context(),
- project_id)
- network = db.fixed_ip_get_network(context.get_admin_context(), address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
-
-
-def lease_ip(private_ip):
- """Run add command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("ISSUE_IP: %s, %s ", out, err)
-
-
-def release_ip(private_ip):
- """Run del command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("RELEASE_IP: %s, %s ", out, err)
diff --git a/nova/tests/test_vlan_network.py b/nova/tests/test_vlan_network.py
new file mode 100644
index 000000000..be39313bb
--- /dev/null
+++ b/nova/tests/test_vlan_network.py
@@ -0,0 +1,373 @@
+# 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.
+"""
+Unit Tests for network code
+"""
+import IPy
+import os
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class VlanNetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(VlanNetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(FLAGS.num_networks):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(VlanNetworkTestCase, self).tearDown()
+
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.VlanManager'):
+ super(VlanNetworkTestCase, self).run(result)
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ 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(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_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']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_public_network_association(self):
+ """Makes sure that we can allocaate a public ip"""
+ # TODO(vish): better way of adding floating ips
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ pubnet = IPy.IP(flags.FLAGS.floating_range)
+ address = str(pubnet[0])
+ try:
+ db.floating_ip_get_by_address(context.get_admin_context(), address)
+ except exception.NotFound:
+ db.floating_ip_create(context.get_admin_context(),
+ {'address': address,
+ 'host': FLAGS.host})
+ float_addr = self.network.allocate_floating_ip(self.context,
+ self.projects[0].id)
+ fix_addr = self._create_address(0)
+ lease_ip(fix_addr)
+ self.assertEqual(float_addr, str(pubnet[0]))
+ self.network.associate_floating_ip(self.context, float_addr, fix_addr)
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, float_addr)
+ self.network.disassociate_floating_ip(self.context, float_addr)
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+ self.network.deallocate_floating_ip(self.context, float_addr)
+ self.network.deallocate_fixed_ip(self.context, fix_addr)
+ release_ip(fix_addr)
+ db.floating_ip_destroy(context.get_admin_context(), float_addr)
+
+ def test_allocate_deallocate_fixed_ip(self):
+ """Makes sure that we can allocate and deallocate a fixed ip"""
+ address = self._create_address(0)
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ lease_ip(address)
+ self._deallocate_address(0, address)
+
+ # Doesn't go away until it's dhcp released
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+
+ release_ip(address)
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ def test_side_effects(self):
+ """Ensures allocating and releasing has no side effects"""
+ address = self._create_address(0)
+ address2 = self._create_address(1, self.instance2_id)
+
+ self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+ self.assertFalse(is_allocated_in_project(address, self.projects[1].id))
+
+ # Addresses are allocated before they're issued
+ lease_ip(address)
+ lease_ip(address2)
+
+ self._deallocate_address(0, address)
+ release_ip(address)
+ self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+
+ # First address release shouldn't affect the second
+ self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+
+ self._deallocate_address(1, address2)
+ release_ip(address2)
+ self.assertFalse(is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ def test_subnet_edge(self):
+ """Makes sure that private ips don't overlap"""
+ first = self._create_address(0)
+ lease_ip(first)
+ instance_ids = []
+ for i in range(1, FLAGS.num_networks):
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(i, instance_ref['id'])
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
+ instance_ids.append(instance_ref['id'])
+ address2 = self._create_address(i, instance_ref['id'])
+ instance_ref = self._create_instance(i, mac=utils.generate_mac())
+ instance_ids.append(instance_ref['id'])
+ address3 = self._create_address(i, instance_ref['id'])
+ lease_ip(address)
+ lease_ip(address2)
+ lease_ip(address3)
+ self.context._project = self.projects[i]
+ self.context.project_id = self.projects[i].id
+ self.assertFalse(is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertFalse(is_allocated_in_project(address2,
+ self.projects[0].id))
+ self.assertFalse(is_allocated_in_project(address3,
+ self.projects[0].id))
+ self.network.deallocate_fixed_ip(self.context, address)
+ self.network.deallocate_fixed_ip(self.context, address2)
+ self.network.deallocate_fixed_ip(self.context, address3)
+ release_ip(address)
+ release_ip(address2)
+ release_ip(address3)
+ for instance_id in instance_ids:
+ db.instance_destroy(context.get_admin_context(), instance_id)
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ self.network.deallocate_fixed_ip(self.context, first)
+ self._deallocate_address(0, first)
+ release_ip(first)
+
+ def test_vpn_ip_and_port_looks_valid(self):
+ """Ensure the vpn ip and port are reasonable"""
+ self.assert_(self.projects[0].vpn_ip)
+ self.assert_(self.projects[0].vpn_port >= FLAGS.vpn_start)
+ self.assert_(self.projects[0].vpn_port <= FLAGS.vpn_start +
+ FLAGS.num_networks)
+
+ def test_too_many_networks(self):
+ """Ensure error is raised if we run out of networks"""
+ projects = []
+ networks_left = (FLAGS.num_networks -
+ db.network_count(context.get_admin_context()))
+ for i in range(networks_left):
+ project = self.manager.create_project('many%s' % i, self.user)
+ projects.append(project)
+ db.project_get_network(context.get_admin_context(), project.id)
+ project = self.manager.create_project('last', self.user)
+ projects.append(project)
+ self.assertRaises(db.NoMoreNetworks,
+ db.project_get_network,
+ context.get_admin_context(),
+ project.id)
+ for project in projects:
+ self.manager.delete_project(project)
+
+ def test_ips_are_reused(self):
+ """Makes sure that ip addresses that are deallocated get reused"""
+ address = self._create_address(0)
+ lease_ip(address)
+ self.network.deallocate_fixed_ip(self.context, address)
+ release_ip(address)
+
+ address2 = self._create_address(0)
+ self.assertEqual(address, address2)
+ lease_ip(address)
+ self.network.deallocate_fixed_ip(self.context, address2)
+ release_ip(address)
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
+
+ def test_too_many_addresses(self):
+ """Test for a NoMoreAddresses exception when all fixed ips are used.
+ """
+ admin_context = context.get_admin_context()
+ network = db.project_get_network(admin_context, self.projects[0].id)
+ num_available_ips = db.network_count_available_ips(admin_context,
+ network['id'])
+ addresses = []
+ instance_ids = []
+ for i in range(num_available_ips):
+ instance_ref = self._create_instance(0)
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(0, instance_ref['id'])
+ addresses.append(address)
+ lease_ip(address)
+
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, 0)
+ self.assertRaises(db.NoMoreAddresses,
+ self.network.allocate_fixed_ip,
+ self.context,
+ 'foo')
+
+ for i in range(num_available_ips):
+ self.network.deallocate_fixed_ip(self.context, addresses[i])
+ release_ip(addresses[i])
+ db.instance_destroy(context.get_admin_context(), instance_ids[i])
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, num_available_ips)
+
+
+def is_allocated_in_project(address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.project_get_network(context.get_admin_context(),
+ project_id)
+ network = db.fixed_ip_get_network(context.get_admin_context(), address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../bin", script))
+
+
+def lease_ip(private_ip):
+ """Run add command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("ISSUE_IP: %s, %s ", out, err)
+
+
+def release_ip(private_ip):
+ """Run del command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("RELEASE_IP: %s, %s ", out, err)
--
cgit
From a74bf3381ada34f35c43d6f307fbae9abecfb255 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Tue, 8 Mar 2011 10:30:48 -0800
Subject: abstracted network code in the base class for flat and vlan
---
nova/network/manager.py | 8 +-
nova/tests/network/__init__.py | 47 +++++++++
nova/tests/network/base.py | 154 ++++++++++++++++++++++++++++++
nova/tests/test_flat_network.py | 147 ++++------------------------
nova/tests/test_vlan_network.py | 205 ++++++++--------------------------------
5 files changed, 259 insertions(+), 302 deletions(-)
create mode 100644 nova/tests/network/__init__.py
create mode 100644 nova/tests/network/base.py
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 686ab9732..670ff55fd 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -404,9 +404,11 @@ class FlatManager(NetworkManager):
net = {}
net['injected'] = FLAGS.flat_injected
net['dns'] = FLAGS.flat_network_dns
- if(FLAGS.use_ipv6):
- net['gateway_v6'] = \
- utils.get_my_linklocal(FLAGS.flat_network_bridge)
+ if not FLAGS.fake_network:
+ if(FLAGS.use_ipv6):
+ net['gateway_v6'] = \
+ utils.get_my_linklocal(
+ FLAGS.flat_network_bridge)
self.db.network_update(context, network_id, net)
def allocate_floating_ip(self, context, project_id):
diff --git a/nova/tests/network/__init__.py b/nova/tests/network/__init__.py
new file mode 100644
index 000000000..e51065983
--- /dev/null
+++ b/nova/tests/network/__init__.py
@@ -0,0 +1,47 @@
+import os
+
+from nova import context
+from nova import db
+from nova import flags
+from nova import log as logging
+from nova import utils
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../../bin", script))
+
+
+def lease_ip(private_ip):
+ """Run add command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("ISSUE_IP: %s, %s ", out, err)
+
+
+def release_ip(private_ip):
+ """Run del command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
+ instance_ref['mac_address'],
+ private_ip)
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(cmd, addl_env=env)
+ LOG.debug("RELEASE_IP: %s, %s ", out, err)
diff --git a/nova/tests/network/base.py b/nova/tests/network/base.py
new file mode 100644
index 000000000..2dd8178ff
--- /dev/null
+++ b/nova/tests/network/base.py
@@ -0,0 +1,154 @@
+# 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.
+"""
+Base class of Unit Tests for all network models
+"""
+import IPy
+import os
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class NetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(NetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(FLAGS.num_networks):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(NetworkTestCase, self).tearDown()
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ def _is_allocated_in_project(self, address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.network_get_by_bridge(context.get_admin_context(),
+ FLAGS.flat_network_bridge)
+ network = db.fixed_ip_get_network(context.get_admin_context(),
+ address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(),
+ address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+ def test_private_ipv6(self):
+ """Make sure ipv6 is OK"""
+ if FLAGS.use_ipv6:
+ instance_ref = self._create_instance(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_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']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
diff --git a/nova/tests/test_flat_network.py b/nova/tests/test_flat_network.py
index 91a49920d..a9a934158 100644
--- a/nova/tests/test_flat_network.py
+++ b/nova/tests/test_flat_network.py
@@ -30,96 +30,15 @@ from nova import log as logging
from nova import test
from nova import utils
from nova.auth import manager
+from nova.tests.network import base
+
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
-class FlatNetworkTestCase(test.TestCase):
+class FlatNetworkTestCase(base.NetworkTestCase):
"""Test cases for network code"""
- def setUp(self):
- super(FlatNetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(5):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(FlatNetworkTestCase, self).tearDown()
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- 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(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_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']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
def test_public_network_association(self):
"""Makes sure that we can allocate a public ip"""
# TODO(vish): better way of adding floating ips
@@ -167,28 +86,34 @@ class FlatNetworkTestCase(test.TestCase):
def test_allocate_deallocate_fixed_ip(self):
"""Makes sure that we can allocate and deallocate a fixed ip"""
address = self._create_address(0)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
self._deallocate_address(0, address)
# check if the fixed ip address is really deallocated
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
def test_side_effects(self):
"""Ensures allocating and releasing has no side effects"""
address = self._create_address(0)
address2 = self._create_address(1, self.instance2_id)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
self._deallocate_address(0, address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
# First address release shouldn't affect the second
- self.assertTrue(is_allocated_in_project(address2, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[0].id))
self._deallocate_address(1, address2)
- self.assertFalse(is_allocated_in_project(address2,
+ self.assertFalse(self._is_allocated_in_project(address2,
self.projects[1].id))
def test_ips_are_reused(self):
@@ -201,29 +126,6 @@ class FlatNetworkTestCase(test.TestCase):
self.network.deallocate_fixed_ip(self.context, address2)
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
-
def test_too_many_addresses(self):
"""Test for a NoMoreAddresses exception when all fixed ips are used.
"""
@@ -257,20 +159,3 @@ class FlatNetworkTestCase(test.TestCase):
def run(self, result=None):
if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
super(FlatNetworkTestCase, self).run(result)
-
-
-def is_allocated_in_project(address, project_id):
- """Returns true if address is in specified project"""
- #project_net = db.project_get_network(context.get_admin_context(),
- # project_id)
- project_net = db.network_get_by_bridge(context.get_admin_context(),
- FLAGS.flat_network_bridge)
- network = db.fixed_ip_get_network(context.get_admin_context(), address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
diff --git a/nova/tests/test_vlan_network.py b/nova/tests/test_vlan_network.py
index be39313bb..f3478320b 100644
--- a/nova/tests/test_vlan_network.py
+++ b/nova/tests/test_vlan_network.py
@@ -29,100 +29,16 @@ from nova import log as logging
from nova import test
from nova import utils
from nova.auth import manager
+from nova.tests.network import base
+from nova.tests.network import binpath,\
+ lease_ip, release_ip
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.tests.network')
-class VlanNetworkTestCase(test.TestCase):
+class VlanNetworkTestCase(base.NetworkTestCase):
"""Test cases for network code"""
- def setUp(self):
- super(VlanNetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(FLAGS.num_networks):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(VlanNetworkTestCase, self).tearDown()
-
- def run(self, result=None):
- if(FLAGS.network_manager == 'nova.network.manager.VlanManager'):
- super(VlanNetworkTestCase, self).run(result)
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- 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(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_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']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
def test_public_network_association(self):
"""Makes sure that we can allocaate a public ip"""
# TODO(vish): better way of adding floating ips
@@ -157,24 +73,30 @@ class VlanNetworkTestCase(test.TestCase):
def test_allocate_deallocate_fixed_ip(self):
"""Makes sure that we can allocate and deallocate a fixed ip"""
address = self._create_address(0)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
lease_ip(address)
self._deallocate_address(0, address)
# Doesn't go away until it's dhcp released
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
def test_side_effects(self):
"""Ensures allocating and releasing has no side effects"""
address = self._create_address(0)
address2 = self._create_address(1, self.instance2_id)
- self.assertTrue(is_allocated_in_project(address, self.projects[0].id))
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
- self.assertFalse(is_allocated_in_project(address, self.projects[1].id))
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[1].id))
# Addresses are allocated before they're issued
lease_ip(address)
@@ -182,14 +104,16 @@ class VlanNetworkTestCase(test.TestCase):
self._deallocate_address(0, address)
release_ip(address)
- self.assertFalse(is_allocated_in_project(address, self.projects[0].id))
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
# First address release shouldn't affect the second
- self.assertTrue(is_allocated_in_project(address2, self.projects[1].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
self._deallocate_address(1, address2)
release_ip(address2)
- self.assertFalse(is_allocated_in_project(address2,
+ self.assertFalse(self._is_allocated_in_project(address2,
self.projects[1].id))
def test_subnet_edge(self):
@@ -212,11 +136,11 @@ class VlanNetworkTestCase(test.TestCase):
lease_ip(address3)
self.context._project = self.projects[i]
self.context.project_id = self.projects[i].id
- self.assertFalse(is_allocated_in_project(address,
+ self.assertFalse(self._is_allocated_in_project(address,
self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address2,
+ self.assertFalse(self._is_allocated_in_project(address2,
self.projects[0].id))
- self.assertFalse(is_allocated_in_project(address3,
+ self.assertFalse(self._is_allocated_in_project(address3,
self.projects[0].id))
self.network.deallocate_fixed_ip(self.context, address)
self.network.deallocate_fixed_ip(self.context, address2)
@@ -270,29 +194,6 @@ class VlanNetworkTestCase(test.TestCase):
self.network.deallocate_fixed_ip(self.context, address2)
release_ip(address)
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
-
def test_too_many_addresses(self):
"""Test for a NoMoreAddresses exception when all fixed ips are used.
"""
@@ -325,49 +226,17 @@ class VlanNetworkTestCase(test.TestCase):
network['id'])
self.assertEqual(ip_count, num_available_ips)
+ def _is_allocated_in_project(self, address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.project_get_network(context.get_admin_context(),
+ project_id)
+ network = db.fixed_ip_get_network(context.get_admin_context(),
+ address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(),
+ address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
-def is_allocated_in_project(address, project_id):
- """Returns true if address is in specified project"""
- project_net = db.project_get_network(context.get_admin_context(),
- project_id)
- network = db.fixed_ip_get_network(context.get_admin_context(), address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(), address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../bin", script))
-
-
-def lease_ip(private_ip):
- """Run add command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s add %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("ISSUE_IP: %s, %s ", out, err)
-
-
-def release_ip(private_ip):
- """Run del command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = "%s del %s %s fake" % (binpath('nova-dhcpbridge'),
- instance_ref['mac_address'],
- private_ip)
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(cmd, addl_env=env)
- LOG.debug("RELEASE_IP: %s, %s ", out, err)
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.VlanManager'):
+ super(VlanNetworkTestCase, self).run(result)
--
cgit
From 80a6dc5504378ae3d96829d96c02f50b9daa3029 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 9 Mar 2011 13:46:05 -0600
Subject: stuff
---
nova/compute/api.py | 15 +++++++++++++--
nova/compute/manager.py | 17 ++++++++++++++---
2 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 33d25fc4b..93f0a12c1 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -456,12 +456,23 @@ class API(base.Base):
self.db.instance_update(context, instance_id,
{'host': migration_ref['dest_compute'], })
- def resize(self, context, instance_id, flavor):
+ def resize(self, context, instance_id, flavor_id):
"""Resize a running instance."""
+ instance = self.db.instance_get(context, instance_id)
+ current_instance_type = self.db.instance_type_get_by_flavor_id(
+ context, instance['flavor_id'])
+ new_instance_type = self.db.instance_type_get_by_flavor_id(
+ context, flavor_id)
+
+ if current_instance_type.memory_mb > new_instance_typ.memory_mb:
+ raise exception.ApiError(_("Invalid flavor: cannot downsize"
+ "instances"))
+
self._cast_scheduler_message(context,
{"method": "prep_resize",
"args": {"topic": FLAGS.compute_topic,
- "instance_id": instance_id, }},)
+ "instance_id": instance_id,
+ "instance_type": new_instance_type}})
def pause(self, context, instance_id):
"""Pause the given instance."""
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index b3e864154..f85ad91df 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -447,7 +447,7 @@ class ComputeManager(manager.Manager):
@exception.wrap_exception
@checks_instance_lock
- def prep_resize(self, context, instance_id):
+ def prep_resize(self, context, instance_id, flavor_id):
"""Initiates the process of moving a running instance to another
host, possibly changing the RAM and disk size in the process"""
context = context.elevated()
@@ -456,12 +456,17 @@ class ComputeManager(manager.Manager):
raise exception.Error(_(
'Migration error: destination same as source!'))
+ instance_type = self.db.instance_type_get_by_flavor_id(context,
+ flavor_id)
migration_ref = self.db.migration_create(context,
{'instance_id': instance_id,
'source_compute': instance_ref['host'],
'dest_compute': FLAGS.host,
'dest_host': self.driver.get_host_ip_addr(),
+ 'old_flavor': instance_type['flavor_id'],
+ 'new_flavor': flavor_id,
'status': 'pre-migrating'})
+
LOG.audit(_('instance %s: migrating to '), instance_id,
context=context)
topic = self.db.queue_get_for(context, FLAGS.compute_topic,
@@ -487,8 +492,14 @@ class ComputeManager(manager.Manager):
self.db.migration_update(context, migration_id,
{'status': 'post-migrating', })
- #TODO(mdietz): This is where we would update the VM record
- #after resizing
+ #TODO(mdietz): apply the rest of the instance_type attributes going
+ #after they're supported
+ self.db.instance_update(context, instance_ref,
+ dict(memory_mb=instance_type['memory_mb'],
+ vcpus=instance_type['vcpus'],
+ local_gb=instance_type['local_gb']))
+ self.driver.resize_instance(context, instance_ref)
+
service = self.db.service_get_by_host_and_topic(context,
migration_ref['dest_compute'], FLAGS.compute_topic)
topic = self.db.queue_get_for(context, FLAGS.compute_topic,
--
cgit
From 25bbe2afb0be3c79264376dd6a11e2bc97847702 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Thu, 10 Mar 2011 11:17:34 -0800
Subject: fixed formatting and redundant imports
---
nova/api/ec2/cloud.py | 6 +++---
.../db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py | 1 -
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 6ed6186be..c6309f03c 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -701,9 +701,9 @@ class CloudController(object):
fixed = instance['fixed_ip']
floating_addr = fixed['floating_ips'][0]['address']
if instance['fixed_ip']['network'] and 'use_v6' in kwargs:
- i['dnsNameV6'] = utils.to_global_ipv6(
- instance['fixed_ip']['network']['cidr_v6'],
- instance['mac_address'])
+ i['dnsNameV6'] = utils.to_global_ipv6(
+ instance['fixed_ip']['network']['cidr_v6'],
+ instance['mac_address'])
i['privateDnsName'] = fixed_addr
i['publicDnsName'] = floating_addr
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
index d14f52af1..b8514c439 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/007_add_ipv6_flatmanager.py
@@ -12,7 +12,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-from lib2to3.fixer_util import String
from sqlalchemy import *
from migrate import *
--
cgit
From 998975651ac2f2df7a3f8af16d62d197f451180f Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 13:53:27 -0800
Subject: Test login. Uncovered bug732866
---
nova/tests/integrated/integrated_helpers.py | 182 ++++++++++++++++++++++++++++
nova/tests/integrated/test_login.py | 77 ++++++++++++
2 files changed, 259 insertions(+)
create mode 100644 nova/tests/integrated/integrated_helpers.py
create mode 100644 nova/tests/integrated/test_login.py
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
new file mode 100644
index 000000000..691ead6e1
--- /dev/null
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -0,0 +1,182 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# 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.
+
+"""
+Provides common functionality for integrated unit tests
+"""
+
+import random
+import string
+
+from nova import exception
+from nova import flags
+from nova import service
+from nova import test # For the flags
+from nova.auth import manager
+from nova.exception import Error
+from nova.log import logging
+from nova.tests.integrated.api import client
+
+
+FLAGS = flags.FLAGS
+
+LOG = logging.getLogger('nova.tests.integrated')
+
+
+def generate_random_alphanumeric(length):
+ """Creates a random alphanumeric string of specified length"""
+ return ''.join(random.choice(string.ascii_uppercase + string.digits)
+ for _x in range(length))
+
+
+def generate_random_numeric(length):
+ """Creates a random numeric string of specified length"""
+ return ''.join(random.choice(string.digits)
+ for _x in range(length))
+
+
+def generate_new_element(items, prefix, numeric=False):
+ """Creates a random string with prefix, that is not in 'items' list"""
+ while True:
+ if numeric:
+ candidate = prefix + generate_random_numeric(8)
+ else:
+ candidate = prefix + generate_random_alphanumeric(8)
+ if not candidate in items:
+ return candidate
+ print "Random collision on %s" % candidate
+
+
+class TestUser(object):
+ def __init__(self, name, secret, auth_url):
+ self.name = name
+ self.secret = secret
+ self.auth_url = auth_url
+
+ if not auth_url:
+ raise exception.Error("auth_url is required")
+ self.openstack_api = client.TestOpenStackClient(self.name,
+ self.secret,
+ self.auth_url)
+
+
+class IntegratedUnitTestContext(object):
+ __INSTANCE = None
+
+ def __init__(self):
+ self.auth_manager = manager.AuthManager()
+
+ self.wsgi_server = None
+ self.wsgi_apps = []
+ self.api_service = None
+
+ self.services = []
+ self.auth_url = None
+ self.project_name = None
+
+ self.setup()
+
+ def setup(self):
+ self._start_services()
+
+ self._create_test_user()
+
+ def _create_test_user(self):
+ self.test_user = self._create_unittest_user()
+
+ # No way to currently pass this through the OpenStack API
+ self.project_name = 'openstack'
+ self._configure_project(self.project_name, self.test_user)
+
+ def _start_services(self):
+ # WSGI shutdown broken :-(
+ if not self.api_service:
+ self._start_api_service()
+
+ def cleanup(self):
+ for service in self.services:
+ service.kill()
+ self.services = []
+ # TODO(justinsb): Shutdown WSGI & anything else we startup
+ # WSGI shutdown broken :-(
+ # self.wsgi_server.terminate()
+ # self.wsgi_server = None
+ self.test_user = None
+
+ def _create_unittest_user(self):
+ users = self.auth_manager.get_users()
+ user_names = [user.name for user in users]
+ auth_name = generate_new_element(user_names, 'unittest_user_')
+ auth_key = generate_random_alphanumeric(16)
+
+ # Right now there's a bug where auth_name and auth_key are reversed
+ auth_key = auth_name
+
+ self.auth_manager.create_user(auth_name, auth_name, auth_key, False)
+ return TestUser(auth_name, auth_key, self.auth_url)
+
+ def _configure_project(self, project_name, user):
+ projects = self.auth_manager.get_projects()
+ project_names = [project.name for project in projects]
+ if not project_name in project_names:
+ project = self.auth_manager.create_project(project_name,
+ user.name,
+ description=None,
+ member_users=None)
+ else:
+ self.auth_manager.add_to_project(user.name, project_name)
+
+ def _start_api_service(self):
+ api_service = service.ApiService.create()
+ api_service.start()
+
+ if not api_service:
+ raise Exception("API Service was None")
+
+ # WSGI shutdown broken :-(
+ #self.services.append(volume_service)
+ self.api_service = api_service
+
+ self.auth_url = 'http://localhost:8774/v1.0'
+
+ return api_service
+
+ # WSGI shutdown broken :-(
+ #@staticmethod
+ #def get():
+ # if not IntegratedUnitTestContext.__INSTANCE:
+ # IntegratedUnitTestContext.startup()
+ # #raise Error("Must call IntegratedUnitTestContext::startup")
+ # return IntegratedUnitTestContext.__INSTANCE
+
+ @staticmethod
+ def startup():
+ # Because WSGI shutdown is broken at the moment, we have to recycle
+ if IntegratedUnitTestContext.__INSTANCE:
+ #raise Error("Multiple calls to IntegratedUnitTestContext.startup")
+ IntegratedUnitTestContext.__INSTANCE.setup()
+ else:
+ IntegratedUnitTestContext.__INSTANCE = IntegratedUnitTestContext()
+ return IntegratedUnitTestContext.__INSTANCE
+
+ @staticmethod
+ def shutdown():
+ if not IntegratedUnitTestContext.__INSTANCE:
+ raise Error("Must call IntegratedUnitTestContext::startup")
+ IntegratedUnitTestContext.__INSTANCE.cleanup()
+ # WSGI shutdown broken :-(
+ #IntegratedUnitTestContext.__INSTANCE = None
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
new file mode 100644
index 000000000..990dcaaf4
--- /dev/null
+++ b/nova/tests/integrated/test_login.py
@@ -0,0 +1,77 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# 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 unittest
+
+from nova import flags
+from nova.log import logging
+from nova.tests.integrated import integrated_helpers
+from nova.tests.integrated.api import client
+
+LOG = logging.getLogger('nova.tests.integrated')
+
+FLAGS = flags.FLAGS
+FLAGS.verbose = True
+
+
+class LoginTest(unittest.TestCase):
+ def setUp(self):
+ super(LoginTest, self).setUp()
+ context = integrated_helpers.IntegratedUnitTestContext.startup()
+ self.user = context.test_user
+ self.api = self.user.openstack_api
+
+ def tearDown(self):
+ integrated_helpers.IntegratedUnitTestContext.shutdown()
+ super(LoginTest, self).tearDown()
+
+ def test_login(self):
+ """Simple check - we list flavors - so we know we're logged in"""
+ flavors = self.api.get_flavors()
+ for flavor in flavors:
+ LOG.debug(_("flavor: %s") % flavor)
+
+ def test_bad_login_password(self):
+ """Test that I get a 401 with a bad username"""
+ bad_credentials_api = client.TestOpenStackClient(self.user.name,
+ "notso_password",
+ self.user.auth_url)
+
+ self.assertRaises(client.OpenstackApiAuthenticationException,
+ bad_credentials_api.get_flavors)
+
+ def test_bad_login_username(self):
+ """Test that I get a 401 with a bad password"""
+ bad_credentials_api = client.TestOpenStackClient("notso_username",
+ self.user.secret,
+ self.user.auth_url)
+
+ self.assertRaises(client.OpenstackApiAuthenticationException,
+ bad_credentials_api.get_flavors)
+
+
+ def test_bad_login_both_bad(self):
+ """Test that I get a 401 with both bad username and bad password"""
+ bad_credentials_api = client.TestOpenStackClient("notso_username",
+ "notso_password",
+ self.user.auth_url)
+
+ self.assertRaises(client.OpenstackApiAuthenticationException,
+ bad_credentials_api.get_flavors)
+
+if __name__ == "__main__":
+ unittest.main()
--
cgit
From 4a9f4f4eef4e6fd6ab84ec2e03437144f9ab62f8 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 10 Mar 2011 16:07:50 -0600
Subject: More resize
---
nova/compute/manager.py | 68 ++++++++++++++++++++++++++++++-----------------
nova/virt/xenapi/vmops.py | 13 +++++++--
nova/virt/xenapi_conn.py | 9 ++++---
3 files changed, 60 insertions(+), 30 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 399356a13..f73e81345 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -429,21 +429,37 @@ class ComputeManager(manager.Manager):
instance_ref = self.db.instance_get(context, instance_id)
migration_ref = self.db.migration_get(context, migration_id)
- #TODO(mdietz): we may want to split these into separate methods.
- if migration_ref['source_compute'] == FLAGS.host:
- self.driver._start(instance_ref)
- self.db.migration_update(context, migration_id,
- {'status': 'reverted'})
- else:
- self.driver.destroy(instance_ref)
- topic = self.db.queue_get_for(context, FLAGS.compute_topic,
- instance_ref['host'])
- rpc.cast(context, topic,
- {'method': 'revert_resize',
- 'args': {
- 'migration_id': migration_ref['id'],
- 'instance_id': instance_id, },
- })
+ self.driver.destroy(instance_ref)
+ topic = self.db.queue_get_for(context, FLAGS.compute_topic,
+ instance_ref['host'])
+ rpc.cast(context, topic,
+ {'method': 'finish_revert_resize',
+ 'args': {
+ 'migration_id': migration_ref['id'],
+ 'instance_id': instance_id, },
+ })
+
+ @exception.wrap_exception
+ @checks_instance_lock
+ def finish_revert_resize(self, context, instance_id, migration_id):
+ """Finishes the second half of reverting a resize, powering back on
+ the source instance and reverting the resized attributes in the
+ database"""
+ instance_ref = self.db.instance_get(context, instance_id)
+ migration_ref = self.db.migration_get(context, migration_id)
+ instance_type = self.db.instance_type_get_by_flavor_id(context,
+ migration_ref['old_flavor_id'])
+
+ #Just roll back the record. There's no need to resize down since
+ #the 'old' VM already has the preferred attributes
+ self.db.instance_update(context,
+ dict(memory_mb=instance_type['memory_mb'],
+ vcpus=instance_type['vcpus'],
+ local_gb=instance_type['local_gb']))
+
+ self.driver._start(instance_ref)
+ self.db.migration_update(context, migration_id,
+ {'status': 'reverted'})
@exception.wrap_exception
@checks_instance_lock
@@ -463,8 +479,8 @@ class ComputeManager(manager.Manager):
'source_compute': instance_ref['host'],
'dest_compute': FLAGS.host,
'dest_host': self.driver.get_host_ip_addr(),
- 'old_flavor': instance_type['flavor_id'],
- 'new_flavor': flavor_id,
+ 'old_flavor_id': instance_type['flavor_id'],
+ 'new_flavor_id': flavor_id,
'status': 'pre-migrating'})
LOG.audit(_('instance %s: migrating to '), instance_id,
@@ -492,13 +508,7 @@ class ComputeManager(manager.Manager):
self.db.migration_update(context, migration_id,
{'status': 'post-migrating', })
- #TODO(mdietz): apply the rest of the instance_type attributes going
- #after they're supported
- self.db.instance_update(context, instance_ref,
- dict(memory_mb=instance_type['memory_mb'],
- vcpus=instance_type['vcpus'],
- local_gb=instance_type['local_gb']))
- self.driver.resize_instance(context, instance_ref)
+
service = self.db.service_get_by_host_and_topic(context,
migration_ref['dest_compute'], FLAGS.compute_topic)
@@ -520,7 +530,17 @@ class ComputeManager(manager.Manager):
migration_ref = self.db.migration_get(context, migration_id)
instance_ref = self.db.instance_get(context,
migration_ref['instance_id'])
+
+ #TODO(mdietz): apply the rest of the instance_type attributes going
+ #after they're supported
+ instance_type = self.db.instance_type_get_by_flavor_id(context,
+ migration_ref['new_flavor_id'])
+ self.db.instance_update(context, instance_ref,
+ dict(memory_mb=instance_type['memory_mb'],
+ vcpus=instance_type['vcpus'],
+ local_gb=instance_type['local_gb']))
+ self.driver.resize_instance(instance_ref, disk_info)
self.driver.finish_resize(instance_ref, disk_info)
self.db.migration_update(context, migration_id,
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 562ecd4d5..9e0bd6a75 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -365,9 +365,18 @@ class VMOps(object):
return new_cow_uuid
- def resize(self, instance, flavor):
+ def resize_instance(self, instance, vdi_uuid):
"""Resize a running instance by changing it's RAM and disk size """
- raise NotImplementedError()
+ vm_ref = VMHelper.lookup(self._session, instance.name)
+ vdi_ref, vm_vdi_rec = \
+ VMHelper.get_vdi_for_vm_safely(self._session, vm_ref)
+ new_disk_size = instance.local_gb
+
+ #TODO(mdietz): this will need to be adjusted for swap later
+ task = self._session.call_xenapi('VDI.resize_online', vdi_ref,
+ new_disk_size)
+ vm_ref = VMHelper.lookup(self._session, instance.name)
+ self._session.wait_for_task(task, instance.id)
def reboot(self, instance):
"""Reboot VM instance"""
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index b63a5f8c3..92b262479 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -158,6 +158,11 @@ class XenAPIConnection(object):
"""Create VM instance"""
self._vmops.spawn(instance)
+ def resize_instance(self, instance, disk_info):
+ """Resizes instance attributes such as RAM and disk space to the
+ attributes specified by the record"""
+ self._vmops.resize_instance(instance, disk_info['cow'])
+
def finish_resize(self, instance, disk_info):
"""Completes a resize, turning on the migrated instance"""
vdi_uuid = self._vmops.attach_disk(instance, disk_info['base_copy'],
@@ -168,10 +173,6 @@ class XenAPIConnection(object):
""" Create snapshot from a running VM instance """
self._vmops.snapshot(instance, image_id)
- def resize(self, instance, flavor):
- """Resize a VM instance"""
- raise NotImplementedError()
-
def reboot(self, instance):
"""Reboot VM instance"""
self._vmops.reboot(instance)
--
cgit
From 3d6430ecd114daa21c72c3d215daaa94f0e87e62 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 14:12:41 -0800
Subject: Re-removed the code that was deleted upstream but somehow didn't get
merged in. Bizarre!
---
nova/tests/integrated/api/client.py | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index 0ce480ae7..da8d87e07 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -172,27 +172,6 @@ class TestOpenStackClient(object):
kwargs.setdefault('check_response_status', [200, 202])
return self.api_request(relative_uri, **kwargs)
- def get_keys_detail(self):
- return self.api_get('/keys/detail')['keys']
-
- def post_key(self, key):
- return self.api_post('/keys', key)['key']
-
- def delete_key(self, key_id):
- return self.api_delete('/keys/%s' % key_id)
-
- def get_volume(self, volume_id):
- return self.api_get('/volumes/%s' % volume_id)['volume']
-
- def get_volumes_detail(self):
- return self.api_get('/volumes/detail')['volumes']
-
- def post_volume(self, volume):
- return self.api_post('/volumes', volume)['volume']
-
- def delete_volume(self, volume_id):
- return self.api_delete('/volumes/%s' % volume_id)
-
def get_server(self, server_id):
return self.api_get('/servers/%s' % server_id)['server']
--
cgit
From 29bc4f5074ca3ada98a25a745077b998b4c5509c Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 14:14:01 -0800
Subject: Pep8 / Style
---
nova/tests/integrated/test_login.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
index 990dcaaf4..e362f92d6 100644
--- a/nova/tests/integrated/test_login.py
+++ b/nova/tests/integrated/test_login.py
@@ -22,6 +22,7 @@ from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
+
LOG = logging.getLogger('nova.tests.integrated')
FLAGS = flags.FLAGS
@@ -63,7 +64,6 @@ class LoginTest(unittest.TestCase):
self.assertRaises(client.OpenstackApiAuthenticationException,
bad_credentials_api.get_flavors)
-
def test_bad_login_both_bad(self):
"""Test that I get a 401 with both bad username and bad password"""
bad_credentials_api = client.TestOpenStackClient("notso_username",
--
cgit
From 0d3e950ed4b0c8abbd619d4ac8724b4c3ce45bf1 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Thu, 10 Mar 2011 14:21:36 -0800
Subject: Document known bug numbers by the code which is degraded until the
bugs are fixed
---
nova/tests/integrated/api/client.py | 1 +
nova/tests/integrated/integrated_helpers.py | 6 ++++++
2 files changed, 7 insertions(+)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index da8d87e07..6fba2930a 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -109,6 +109,7 @@ class TestOpenStackClient(object):
LOG.debug(_("%(auth_uri)s => code %(http_status)s") % locals())
# Until bug732866 is fixed, we can't check this properly...
+ # bug732866
#if http_status == 401:
if http_status != 204:
raise OpenstackApiAuthenticationException(response=response)
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
index 691ead6e1..47093636e 100644
--- a/nova/tests/integrated/integrated_helpers.py
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -104,6 +104,7 @@ class IntegratedUnitTestContext(object):
def _start_services(self):
# WSGI shutdown broken :-(
+ # bug731668
if not self.api_service:
self._start_api_service()
@@ -112,6 +113,7 @@ class IntegratedUnitTestContext(object):
service.kill()
self.services = []
# TODO(justinsb): Shutdown WSGI & anything else we startup
+ # bug731668
# WSGI shutdown broken :-(
# self.wsgi_server.terminate()
# self.wsgi_server = None
@@ -124,6 +126,7 @@ class IntegratedUnitTestContext(object):
auth_key = generate_random_alphanumeric(16)
# Right now there's a bug where auth_name and auth_key are reversed
+ # bug732907
auth_key = auth_name
self.auth_manager.create_user(auth_name, auth_name, auth_key, False)
@@ -156,6 +159,7 @@ class IntegratedUnitTestContext(object):
return api_service
# WSGI shutdown broken :-(
+ # bug731668
#@staticmethod
#def get():
# if not IntegratedUnitTestContext.__INSTANCE:
@@ -166,6 +170,7 @@ class IntegratedUnitTestContext(object):
@staticmethod
def startup():
# Because WSGI shutdown is broken at the moment, we have to recycle
+ # bug731668
if IntegratedUnitTestContext.__INSTANCE:
#raise Error("Multiple calls to IntegratedUnitTestContext.startup")
IntegratedUnitTestContext.__INSTANCE.setup()
@@ -179,4 +184,5 @@ class IntegratedUnitTestContext(object):
raise Error("Must call IntegratedUnitTestContext::startup")
IntegratedUnitTestContext.__INSTANCE.cleanup()
# WSGI shutdown broken :-(
+ # bug731668
#IntegratedUnitTestContext.__INSTANCE = None
--
cgit
From e891e48b63065a7218627289a908aece0f6a3730 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 11 Mar 2011 10:31:08 -0800
Subject: Made changes to xs-ipv6 code impacted because of addition of
flatmanger ipv6 support
---
nova/virt/xenapi/vmops.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 9ac83efb0..52d2652f9 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -617,9 +617,10 @@ class VMOps(object):
def ip6_dict(ip6):
return {
- "ip": ip6.addressV6,
- "netmask": ip6.netmaskV6,
- "gateway": ip6.gatewayV6,
+ "ip": utils.to_global_ipv6(network['cidr_v6'],
+ instance['mac_address']),
+ "netmask": network['netmask_v6'],
+ "gateway": network['gateway_v6'],
"enabled": "1"}
mac_id = instance.mac_address.replace(':', '')
--
cgit
From 6cd90a95d632d45d1c906d412e3240f730e88b95 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Fri, 11 Mar 2011 15:35:55 -0600
Subject: New migration
---
.../versions/010_add_flavors_to_migrations.py | 44 ++++++++++++++++++++++
nova/db/sqlalchemy/models.py | 2 +
nova/tests/test_compute.py | 2 -
3 files changed, 46 insertions(+), 2 deletions(-)
create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py
new file mode 100644
index 000000000..412caedd0
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py
@@ -0,0 +1,44 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 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.from sqlalchemy import *
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+migrations = Table('migrations', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+#
+# Tables to alter
+#
+#
+
+old_flavor_id = Column('old_flavor_id', Integer())
+new_flavor_id = Column('new_flavor_id', Integer())
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+ migrations.create_column(old_flavor_id)
+ migrations.create_column(new_flavor_id)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 6ef284e65..73cd8a4cc 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -396,6 +396,8 @@ class Migration(BASE, NovaBase):
source_compute = Column(String(255))
dest_compute = Column(String(255))
dest_host = Column(String(255))
+ old_flavor_id = Column(Integer())
+ new_flavor_id = Column(Integer())
instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True)
#TODO(_cerberus_): enum
status = Column(String(255))
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 643b2e93a..3d25a8997 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -299,5 +299,3 @@ class ComputeTestCase(test.TestCase):
self.assertRaises(exception.Error, self.compute.prep_resize,
self.context, instance_id)
self.compute.terminate_instance(self.context, instance_id)
- type = instance_types.get_by_flavor_id("1")
- self.assertEqual(type, 'm1.tiny')
--
cgit
From bacce305a99dff77aa0e24c64cb937514e368ec1 Mon Sep 17 00:00:00 2001
From: Anne Gentle
Date: Fri, 11 Mar 2011 17:13:56 -0600
Subject: Adding a sidebar element to the nova.openstack.org site to point
people to additional versions of the site.
---
doc/source/_static/tweaks.css | 147 ++++++++++++++++++++++++++++++++++++++++++
doc/source/_theme/layout.html | 11 +++-
2 files changed, 157 insertions(+), 1 deletion(-)
diff --git a/doc/source/_static/tweaks.css b/doc/source/_static/tweaks.css
index 1a18dbac6..7c57c8f35 100644
--- a/doc/source/_static/tweaks.css
+++ b/doc/source/_static/tweaks.css
@@ -69,3 +69,150 @@ table.docutils {
.tweet_list li .tweet_avatar {
float: left;
}
+
+/* ------------------------------------------
+PURE CSS SPEECH BUBBLES
+by Nicolas Gallagher
+- http://nicolasgallagher.com/pure-css-speech-bubbles/
+
+http://nicolasgallagher.com
+http://twitter.com/necolas
+
+Created: 02 March 2010
+Version: 1.1 (21 October 2010)
+
+Dual licensed under MIT and GNU GPLv2 © Nicolas Gallagher
+------------------------------------------ */
+/* THE SPEECH BUBBLE
+------------------------------------------------------------------------------------------------------------------------------- */
+
+/* THE SPEECH BUBBLE
+------------------------------------------------------------------------------------------------------------------------------- */
+
+.triangle-border {
+ position:relative;
+ padding:15px;
+ margin:1em 0 3em;
+ border:5px solid #BC1518;
+ color:#333;
+ background:#fff;
+
+ /* css3 */
+ -moz-border-radius:10px;
+ -webkit-border-radius:10px;
+ border-radius:10px;
+}
+
+/* Variant : for left positioned triangle
+------------------------------------------ */
+
+.triangle-border.left {
+ margin-left:30px;
+}
+
+/* Variant : for right positioned triangle
+------------------------------------------ */
+
+.triangle-border.right {
+ margin-right:30px;
+}
+
+/* THE TRIANGLE
+------------------------------------------------------------------------------------------------------------------------------- */
+
+.triangle-border:before {
+ content:"";
+ display:block; /* reduce the damage in FF3.0 */
+ position:absolute;
+ bottom:-40px; /* value = - border-top-width - border-bottom-width */
+ left:40px; /* controls horizontal position */
+ width:0;
+ height:0;
+ border:20px solid transparent;
+ border-top-color:#BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border:after {
+ content:"";
+ display:block; /* reduce the damage in FF3.0 */
+ position:absolute;
+ bottom:-26px; /* value = - border-top-width - border-bottom-width */
+ left:47px; /* value = (:before left) + (:before border-left) - (:after border-left) */
+ width:0;
+ height:0;
+ border:13px solid transparent;
+ border-top-color:#fff;
+}
+
+/* Variant : top
+------------------------------------------ */
+
+/* creates the larger triangle */
+.triangle-border.top:before {
+ top:-40px; /* value = - border-top-width - border-bottom-width */
+ right:40px; /* controls horizontal position */
+ bottom:auto;
+ left:auto;
+ border:20px solid transparent;
+ border-bottom-color:#BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border.top:after {
+ top:-26px; /* value = - border-top-width - border-bottom-width */
+ right:47px; /* value = (:before right) + (:before border-right) - (:after border-right) */
+ bottom:auto;
+ left:auto;
+ border:13px solid transparent;
+ border-bottom-color:#fff;
+}
+
+/* Variant : left
+------------------------------------------ */
+
+/* creates the larger triangle */
+.triangle-border.left:before {
+ top:10px; /* controls vertical position */
+ left:-30px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ border-width:15px 30px 15px 0;
+ border-style:solid;
+ border-color:transparent #BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border.left:after {
+ top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */
+ left:-21px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ border-width:9px 21px 9px 0;
+ border-style:solid;
+ border-color:transparent #fff;
+}
+
+/* Variant : right
+------------------------------------------ */
+
+/* creates the larger triangle */
+.triangle-border.right:before {
+ top:10px; /* controls vertical position */
+ right:-30px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ left:auto;
+ border-width:15px 0 15px 30px;
+ border-style:solid;
+ border-color:transparent #BC1518;
+}
+
+/* creates the smaller triangle */
+.triangle-border.right:after {
+ top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */
+ right:-21px; /* value = - border-left-width - border-right-width */
+ bottom:auto;
+ left:auto;
+ border-width:9px 0 9px 21px;
+ border-style:solid;
+ border-color:transparent #fff;
+}
+
diff --git a/doc/source/_theme/layout.html b/doc/source/_theme/layout.html
index e3eb54b71..958c512e4 100644
--- a/doc/source/_theme/layout.html
+++ b/doc/source/_theme/layout.html
@@ -71,12 +71,21 @@
+
+
+ Psst... hey. You're reading the latest content, but it might be out of sync with code. You can read Nova 2011.1 docs or all OpenStack docs too.
+
+
{%- endif %}
{%- if pagename == "index" %}
- {{ _('Twitter Feed') }}
+
+
+ {{ _('Twitter Feed') }}
{%- endif %}
+
+
{%- endblock %}
--
cgit
From 1c4afe23157233b7081872ccbc6ea5fa1ff0015a Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Fri, 11 Mar 2011 17:30:51 -0600
Subject: Some unit tests
---
nova/compute/api.py | 9 ++++++---
nova/tests/test_compute.py | 24 ++++++++++++++++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 1393c01d5..0dc2bb3d3 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -460,10 +460,13 @@ class API(base.Base):
def resize(self, context, instance_id, flavor_id):
"""Resize a running instance."""
instance = self.db.instance_get(context, instance_id)
- current_instance_type = self.db.instance_type_get_by_flavor_id(
- context, instance['flavor_id'])
+ current_instance_type = self.db.instance_type_get_by_name(
+ context, instance['instance_type'])
+
new_instance_type = self.db.instance_type_get_by_flavor_id(
- context, flavor_id)
+ context, flavor_id)
+ if not new_instance_type:
+ raise exception.ApiError(_("Requested flavor does not exist"))
if current_instance_type.memory_mb > new_instance_typ.memory_mb:
raise exception.ApiError(_("Invalid flavor: cannot downsize"
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 3d25a8997..c53284216 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -287,6 +287,30 @@ class ComputeTestCase(test.TestCase):
migration_ref['id'])
self.compute.terminate_instance(context, instance_id)
+ def test_resize_invalid_flavor_fails(self):
+ """Ensure invalid flavors raise"""
+ instance_id = self._create_instance()
+ context = self.context.elevated()
+ self.compute.run_instance(self.context, instance_id)
+
+ self.assertRaises(exception.ApiError, self.compute_api.resize,
+ context, instance_id, 200)
+
+ self.compute.terminate_instance(context, instance_id)
+
+ def test_resize_down_fails(self):
+ """Ensure invalid flavors raise"""
+ instance_id = self._create_instance()
+ context = self.context.elevated()
+ self.compute.run_instance(self.context, instance_id)
+ db.instance_update(self.context, instance_id,
+ {'instance_type': 'm1.large'})
+
+ self.assertRaises(exception.ApiError, self.compute_api.resize,
+ context, instance_id, 1)
+
+ self.compute.terminate_instance(context, instance_id)
+
def test_get_by_flavor_id(self):
type = instance_types.get_by_flavor_id(1)
self.assertEqual(type, 'm1.tiny')
--
cgit
From d45947d83fa22f98b0889d269d447fabaa764a3c Mon Sep 17 00:00:00 2001
From: Anne Gentle
Date: Mon, 14 Mar 2011 09:48:58 -0500
Subject: Fixes link to 2011.1 instad of just to trunk docs
---
doc/source/_theme/layout.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/source/_theme/layout.html b/doc/source/_theme/layout.html
index 958c512e4..0a37a7943 100644
--- a/doc/source/_theme/layout.html
+++ b/doc/source/_theme/layout.html
@@ -73,7 +73,7 @@
- Psst... hey. You're reading the latest content, but it might be out of sync with code. You can read Nova 2011.1 docs or all OpenStack docs too.
+ Psst... hey. You're reading the latest content, but it might be out of sync with code. You can read Nova 2011.1 docs or all OpenStack docs too.
{%- endif %}
--
cgit
From af5e752e8eb21d0e9192d9acd9e75586bdec3685 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Mon, 14 Mar 2011 11:55:55 -0500
Subject: Compute test
---
nova/tests/test_compute.py | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index c53284216..47e0f66fb 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -76,6 +76,20 @@ class ComputeTestCase(test.TestCase):
inst.update(params)
return db.instance_create(self.context, inst)['id']
+ def _create_instance_type(self, params={}):
+ """Create a test instance"""
+ inst = {}
+ inst['name'] = 'm1.small'
+ inst['memory_mb'] = '1024'
+ inst['vcpus'] = '1'
+ inst['local_gb'] = '20'
+ inst['flavorid'] = '1'
+ inst['swap'] = '2048'
+ inst['rxtx_quota'] = 100
+ inst['rxtx_cap'] = 200
+ inst.update(params)
+ return db.instance_type_create(self.context, inst)['id']
+
def _create_group(self):
values = {'name': 'testgroup',
'description': 'testgroup',
@@ -301,10 +315,17 @@ class ComputeTestCase(test.TestCase):
def test_resize_down_fails(self):
"""Ensure invalid flavors raise"""
instance_id = self._create_instance()
+
+ small_inst_type_id = self._create_instance_type(dict(flavorid=1,
+ memory_mb=512))
+ big_inst_type_id = self._create_instance_type(dict(flavorid=2,
+ name='m1.wowzers', memory_mb=8192))
+
context = self.context.elevated()
self.compute.run_instance(self.context, instance_id)
- db.instance_update(self.context, instance_id,
- {'instance_type': 'm1.large'})
+ db.instance_update(self.context, instance_id,
+ {'instance_type': 'm1.wowzers',
+ 'memory_gb': 8192})
self.assertRaises(exception.ApiError, self.compute_api.resize,
context, instance_id, 1)
--
cgit
From 1f763599d733de1ded1074dee828237256eda01d Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Mon, 14 Mar 2011 16:59:46 +0000
Subject: Migration moved again
---
.../versions/010_add_flavors_to_migrations.py | 44 ----------------------
.../versions/011_add_flavors_to_migrations.py | 44 ++++++++++++++++++++++
2 files changed, 44 insertions(+), 44 deletions(-)
delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py
create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py
deleted file mode 100644
index 412caedd0..000000000
--- a/nova/db/sqlalchemy/migrate_repo/versions/010_add_flavors_to_migrations.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 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.from sqlalchemy import *
-
-from sqlalchemy import *
-from migrate import *
-
-from nova import log as logging
-
-
-meta = MetaData()
-
-migrations = Table('migrations', meta,
- Column('id', Integer(), primary_key=True, nullable=False),
- )
-
-#
-# Tables to alter
-#
-#
-
-old_flavor_id = Column('old_flavor_id', Integer())
-new_flavor_id = Column('new_flavor_id', Integer())
-
-
-def upgrade(migrate_engine):
- # Upgrade operations go here. Don't create your own engine;
- # bind migrate_engine to your metadata
- meta.bind = migrate_engine
- migrations.create_column(old_flavor_id)
- migrations.create_column(new_flavor_id)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py
new file mode 100644
index 000000000..412caedd0
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py
@@ -0,0 +1,44 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 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.from sqlalchemy import *
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+migrations = Table('migrations', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+#
+# Tables to alter
+#
+#
+
+old_flavor_id = Column('old_flavor_id', Integer())
+new_flavor_id = Column('new_flavor_id', Integer())
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+ migrations.create_column(old_flavor_id)
+ migrations.create_column(new_flavor_id)
--
cgit
From 1ebae577150ce64d81d102c2e162acfe5a72528b Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Mon, 14 Mar 2011 12:07:27 -0500
Subject: Test changes
---
nova/compute/api.py | 2 +-
nova/tests/test_compute.py | 15 ++++++++++++---
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 3920f2af8..9d238c7d0 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -482,7 +482,7 @@ class API(base.Base):
{"method": "prep_resize",
"args": {"topic": FLAGS.compute_topic,
"instance_id": instance_id,
- "instance_type": new_instance_type}})
+ "flavor_id": flavor_id}})
def pause(self, context, instance_id):
"""Pause the given instance."""
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 47e0f66fb..265421837 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -292,14 +292,18 @@ class ComputeTestCase(test.TestCase):
"""Ensure instance can be migrated/resized"""
instance_id = self._create_instance()
context = self.context.elevated()
+ small_inst_type_id = self._create_instance_type(dict(flavorid=1,
+ memory_mb=512, name='m1.small'))
+
self.compute.run_instance(self.context, instance_id)
db.instance_update(self.context, instance_id, {'host': 'foo'})
- self.compute.prep_resize(context, instance_id)
+ self.compute.prep_resize(context, instance_id, 1)
migration_ref = db.migration_get_by_instance_and_status(context,
instance_id, 'pre-migrating')
self.compute.resize_instance(context, instance_id,
migration_ref['id'])
self.compute.terminate_instance(context, instance_id)
+ self.db.instance_type_purge(context, 'm1.small')
def test_resize_invalid_flavor_fails(self):
"""Ensure invalid flavors raise"""
@@ -317,7 +321,7 @@ class ComputeTestCase(test.TestCase):
instance_id = self._create_instance()
small_inst_type_id = self._create_instance_type(dict(flavorid=1,
- memory_mb=512))
+ memory_mb=512, name='m1.small'))
big_inst_type_id = self._create_instance_type(dict(flavorid=2,
name='m1.wowzers', memory_mb=8192))
@@ -331,6 +335,8 @@ class ComputeTestCase(test.TestCase):
context, instance_id, 1)
self.compute.terminate_instance(context, instance_id)
+ self.db.instance_type_purge(context, 'm1.small')
+ self.db.instance_type_purge(context, 'm1.wowzers')
def test_get_by_flavor_id(self):
type = instance_types.get_by_flavor_id(1)
@@ -340,7 +346,10 @@ class ComputeTestCase(test.TestCase):
"""Ensure instance fails to migrate when source and destination are
the same host"""
instance_id = self._create_instance()
+ small_inst_type_id = self._create_instance_type(dict(flavorid=1,
+ memory_mb=512, name='m1.small'))
self.compute.run_instance(self.context, instance_id)
self.assertRaises(exception.Error, self.compute.prep_resize,
- self.context, instance_id)
+ self.context, instance_id, 1)
self.compute.terminate_instance(self.context, instance_id)
+ self.db.instance_type_purge(context, 'm1.small')
--
cgit
From e509cd70e7a2e8a430b2b24af50adcf1ad763564 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Mon, 14 Mar 2011 17:24:39 +0000
Subject: Test fixes and some typos
---
nova/compute/api.py | 4 ++--
nova/compute/manager.py | 2 +-
nova/db/sqlalchemy/api.py | 4 ++--
nova/tests/test_compute.py | 23 +++++------------------
4 files changed, 10 insertions(+), 23 deletions(-)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 9d238c7d0..0e9bf2424 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -468,13 +468,13 @@ class API(base.Base):
instance = self.db.instance_get(context, instance_id)
current_instance_type = self.db.instance_type_get_by_name(
context, instance['instance_type'])
-
+
new_instance_type = self.db.instance_type_get_by_flavor_id(
context, flavor_id)
if not new_instance_type:
raise exception.ApiError(_("Requested flavor does not exist"))
- if current_instance_type.memory_mb > new_instance_typ.memory_mb:
+ if current_instance_type['memory_mb'] > new_instance_type['memory_mb']:
raise exception.ApiError(_("Invalid flavor: cannot downsize"
"instances"))
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index f73e81345..57d175ec7 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -479,7 +479,7 @@ class ComputeManager(manager.Manager):
'source_compute': instance_ref['host'],
'dest_compute': FLAGS.host,
'dest_host': self.driver.get_host_ip_addr(),
- 'old_flavor_id': instance_type['flavor_id'],
+ 'old_flavor_id': instance_type['flavorid'],
'new_flavor_id': flavor_id,
'status': 'pre-migrating'})
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 8b541757a..50267e21f 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2185,8 +2185,8 @@ def instance_type_create(_context, values):
instance_type_ref = models.InstanceTypes()
instance_type_ref.update(values)
instance_type_ref.save()
- except:
- raise exception.DBError
+ except Exception, e:
+ raise exception.DBError(e)
return instance_type_ref
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 265421837..a6defd644 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -78,6 +78,7 @@ class ComputeTestCase(test.TestCase):
def _create_instance_type(self, params={}):
"""Create a test instance"""
+ context = self.context.elevated()
inst = {}
inst['name'] = 'm1.small'
inst['memory_mb'] = '1024'
@@ -88,7 +89,7 @@ class ComputeTestCase(test.TestCase):
inst['rxtx_quota'] = 100
inst['rxtx_cap'] = 200
inst.update(params)
- return db.instance_type_create(self.context, inst)['id']
+ return db.instance_type_create(context, inst)['id']
def _create_group(self):
values = {'name': 'testgroup',
@@ -292,8 +293,6 @@ class ComputeTestCase(test.TestCase):
"""Ensure instance can be migrated/resized"""
instance_id = self._create_instance()
context = self.context.elevated()
- small_inst_type_id = self._create_instance_type(dict(flavorid=1,
- memory_mb=512, name='m1.small'))
self.compute.run_instance(self.context, instance_id)
db.instance_update(self.context, instance_id, {'host': 'foo'})
@@ -303,7 +302,6 @@ class ComputeTestCase(test.TestCase):
self.compute.resize_instance(context, instance_id,
migration_ref['id'])
self.compute.terminate_instance(context, instance_id)
- self.db.instance_type_purge(context, 'm1.small')
def test_resize_invalid_flavor_fails(self):
"""Ensure invalid flavors raise"""
@@ -311,32 +309,24 @@ class ComputeTestCase(test.TestCase):
context = self.context.elevated()
self.compute.run_instance(self.context, instance_id)
- self.assertRaises(exception.ApiError, self.compute_api.resize,
+ self.assertRaises(exception.NotFound, self.compute_api.resize,
context, instance_id, 200)
self.compute.terminate_instance(context, instance_id)
def test_resize_down_fails(self):
"""Ensure invalid flavors raise"""
+ context = self.context.elevated()
instance_id = self._create_instance()
- small_inst_type_id = self._create_instance_type(dict(flavorid=1,
- memory_mb=512, name='m1.small'))
- big_inst_type_id = self._create_instance_type(dict(flavorid=2,
- name='m1.wowzers', memory_mb=8192))
-
- context = self.context.elevated()
self.compute.run_instance(self.context, instance_id)
db.instance_update(self.context, instance_id,
- {'instance_type': 'm1.wowzers',
- 'memory_gb': 8192})
+ {'instance_type': 'm1.xlarge'})
self.assertRaises(exception.ApiError, self.compute_api.resize,
context, instance_id, 1)
self.compute.terminate_instance(context, instance_id)
- self.db.instance_type_purge(context, 'm1.small')
- self.db.instance_type_purge(context, 'm1.wowzers')
def test_get_by_flavor_id(self):
type = instance_types.get_by_flavor_id(1)
@@ -346,10 +336,7 @@ class ComputeTestCase(test.TestCase):
"""Ensure instance fails to migrate when source and destination are
the same host"""
instance_id = self._create_instance()
- small_inst_type_id = self._create_instance_type(dict(flavorid=1,
- memory_mb=512, name='m1.small'))
self.compute.run_instance(self.context, instance_id)
self.assertRaises(exception.Error, self.compute.prep_resize,
self.context, instance_id, 1)
self.compute.terminate_instance(self.context, instance_id)
- self.db.instance_type_purge(context, 'm1.small')
--
cgit
From 06051ac8660983aae9ea6e72ab9bb1a31ceed9af Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Mon, 14 Mar 2011 11:08:00 -0700
Subject: Reverted unmodified files
---
tools/ajaxterm/README.txt | 240 +++++++++++++++++++++++-----------------------
1 file changed, 120 insertions(+), 120 deletions(-)
diff --git a/tools/ajaxterm/README.txt b/tools/ajaxterm/README.txt
index a649771c5..4b0ae99af 100644
--- a/tools/ajaxterm/README.txt
+++ b/tools/ajaxterm/README.txt
@@ -1,120 +1,120 @@
-= [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] =
-
-Ajaxterm is a web based terminal. It was totally inspired and works almost
-exactly like http://anyterm.org/ except it's much easier to install (see
-comparaison with anyterm below).
-
-Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]]
-Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]]
-Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain.
-
-Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark.
-
-== News ==
-
- * 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init
- * 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer)
- * 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256
- * 2006-05-31: v0.7 minor fixes, daemon option
- * 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022
-
-== Download and Install ==
-
- * Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz]
- * Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/]
-
-To install Ajaxterm issue the following commands:
-{{{
-wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz
-tar zxvf Ajaxterm-0.10.tar.gz
-cd Ajaxterm-0.10
-./ajaxterm.py
-}}}
-Then point your browser to this URL : http://localhost:8022/
-
-== Screenshot ==
-
-{{{
-#!html
-
-}}}
-
-== Documentation and Caveats ==
-
- * Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG".
-
- * If run as root ajaxterm will run /bin/login, otherwise it will run ssh
- localhost. To use an other command use the -c option.
-
- * By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is
- strongly recommended to use '''https SSL/TLS''', and that is simple to
- configure if you use the apache web server using mod_proxy.[[BR]][[BR]]
- Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]]
- Here is an configuration example:
-
-{{{
- Listen 443
- NameVirtualHost *:443
-
-
- ServerName localhost
- SSLEngine On
- SSLCertificateKeyFile ssl/apache.pem
- SSLCertificateFile ssl/apache.pem
-
- ProxyRequests Off
-
- Order deny,allow
- Allow from all
-
- ProxyPass /ajaxterm/ http://localhost:8022/
- ProxyPassReverse /ajaxterm/ http://localhost:8022/
-
-}}}
-
- * Using GET HTTP request seems to speed up ajaxterm, just click on GET in the
- interface, but be warned that your keystrokes might be loggued (by apache or
- any proxy). I usually enable it after the login.
-
- * Ajaxterm commandline usage:
-
-{{{
-usage: ajaxterm.py [options]
-
-options:
- -h, --help show this help message and exit
- -pPORT, --port=PORT Set the TCP port (default: 8022)
- -cCMD, --command=CMD set the command (default: /bin/login or ssh localhost)
- -l, --log log requests to stderr (default: quiet mode)
- -d, --daemon run as daemon in the background
- -PPIDFILE, --pidfile=PIDFILE
- set the pidfile (default: /var/run/ajaxterm.pid)
- -iINDEX_FILE, --index=INDEX_FILE
- default index file (default: ajaxterm.html)
- -uUID, --uid=UID Set the daemon's user id
-}}}
-
- * Ajaxterm was first written as a demo for qweb (my web framework), but
- actually doesn't use many features of qweb.
-
- * Compared to anyterm:
- * There are no partial updates, ajaxterm updates either all the screen or
- nothing. That make the code simpler and I also think it's faster. HTTP
- replies are always gzencoded. When used in 80x25 mode, almost all of
- them are below the 1500 bytes (size of an ethernet frame) and we just
- replace the screen with the reply (no javascript string handling).
- * Ajaxterm polls the server for updates with an exponentially growing
- timeout when the screen hasn't changed. The timeout is also resetted as
- soon as a key is pressed. Anyterm blocks on a pending request and use a
- parallel connection for keypresses. The anyterm approch is better
- when there aren't any keypress.
-
- * Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL).
-
-== TODO ==
-
- * insert mode ESC [ 4 h
- * change size x,y from gui (sending signal)
- * vt102 graphic codepage
- * use innerHTML or prototype instead of sarissa
-
+= [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] =
+
+Ajaxterm is a web based terminal. It was totally inspired and works almost
+exactly like http://anyterm.org/ except it's much easier to install (see
+comparaison with anyterm below).
+
+Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]]
+Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]]
+Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain.
+
+Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark.
+
+== News ==
+
+ * 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init
+ * 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer)
+ * 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256
+ * 2006-05-31: v0.7 minor fixes, daemon option
+ * 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022
+
+== Download and Install ==
+
+ * Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz]
+ * Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/]
+
+To install Ajaxterm issue the following commands:
+{{{
+wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz
+tar zxvf Ajaxterm-0.10.tar.gz
+cd Ajaxterm-0.10
+./ajaxterm.py
+}}}
+Then point your browser to this URL : http://localhost:8022/
+
+== Screenshot ==
+
+{{{
+#!html
+
+}}}
+
+== Documentation and Caveats ==
+
+ * Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG".
+
+ * If run as root ajaxterm will run /bin/login, otherwise it will run ssh
+ localhost. To use an other command use the -c option.
+
+ * By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is
+ strongly recommended to use '''https SSL/TLS''', and that is simple to
+ configure if you use the apache web server using mod_proxy.[[BR]][[BR]]
+ Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]]
+ Here is an configuration example:
+
+{{{
+ Listen 443
+ NameVirtualHost *:443
+
+
+ ServerName localhost
+ SSLEngine On
+ SSLCertificateKeyFile ssl/apache.pem
+ SSLCertificateFile ssl/apache.pem
+
+ ProxyRequests Off
+
+ Order deny,allow
+ Allow from all
+
+ ProxyPass /ajaxterm/ http://localhost:8022/
+ ProxyPassReverse /ajaxterm/ http://localhost:8022/
+
+}}}
+
+ * Using GET HTTP request seems to speed up ajaxterm, just click on GET in the
+ interface, but be warned that your keystrokes might be loggued (by apache or
+ any proxy). I usually enable it after the login.
+
+ * Ajaxterm commandline usage:
+
+{{{
+usage: ajaxterm.py [options]
+
+options:
+ -h, --help show this help message and exit
+ -pPORT, --port=PORT Set the TCP port (default: 8022)
+ -cCMD, --command=CMD set the command (default: /bin/login or ssh localhost)
+ -l, --log log requests to stderr (default: quiet mode)
+ -d, --daemon run as daemon in the background
+ -PPIDFILE, --pidfile=PIDFILE
+ set the pidfile (default: /var/run/ajaxterm.pid)
+ -iINDEX_FILE, --index=INDEX_FILE
+ default index file (default: ajaxterm.html)
+ -uUID, --uid=UID Set the daemon's user id
+}}}
+
+ * Ajaxterm was first written as a demo for qweb (my web framework), but
+ actually doesn't use many features of qweb.
+
+ * Compared to anyterm:
+ * There are no partial updates, ajaxterm updates either all the screen or
+ nothing. That make the code simpler and I also think it's faster. HTTP
+ replies are always gzencoded. When used in 80x25 mode, almost all of
+ them are below the 1500 bytes (size of an ethernet frame) and we just
+ replace the screen with the reply (no javascript string handling).
+ * Ajaxterm polls the server for updates with an exponentially growing
+ timeout when the screen hasn't changed. The timeout is also resetted as
+ soon as a key is pressed. Anyterm blocks on a pending request and use a
+ parallel connection for keypresses. The anyterm approch is better
+ when there aren't any keypress.
+
+ * Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL).
+
+== TODO ==
+
+ * insert mode ESC [ 4 h
+ * change size x,y from gui (sending signal)
+ * vt102 graphic codepage
+ * use innerHTML or prototype instead of sarissa
+
--
cgit
--
cgit
--
cgit
From c94ec9a5bab6c07b402b68e2f4ff081247a27cda Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 14:17:58 -0700
Subject: Initial implementation of refresh instance states
---
nova/compute/driver.py | 38 ++++++++++++++++++++++++++++++
nova/compute/manager.py | 56 ++++++++++++++++++++++++++++++++++++++++++++-
nova/compute/power_state.py | 16 +++++++++----
nova/utils.py | 9 ++++++++
nova/virt/connection.py | 4 +++-
nova/virt/fake.py | 36 +++++++++++++++++++++--------
nova/virt/hyperv.py | 4 +++-
nova/virt/libvirt_conn.py | 24 ++++++++++++++++++-
nova/virt/xenapi/vmops.py | 19 +++++++++++++++
nova/virt/xenapi_conn.py | 7 +++++-
10 files changed, 194 insertions(+), 19 deletions(-)
create mode 100644 nova/compute/driver.py
diff --git a/nova/compute/driver.py b/nova/compute/driver.py
new file mode 100644
index 000000000..bda82c60a
--- /dev/null
+++ b/nova/compute/driver.py
@@ -0,0 +1,38 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# 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.
+
+"""
+Driver base-classes:
+
+ (Beginning of) the contract that compute drivers must follow, and shared
+ types that support that contract
+"""
+
+from nova.compute import power_state
+
+
+class InstanceInfo(object):
+ def __init__(self, name, state):
+ self.name = name
+ assert state in power_state.valid_states()
+ self.state = state
+
+
+class ComputeDriver(object):
+ def list_instances_detail(self):
+ """Return a list of InstanceInfo for all registered VMs"""
+ raise NotImplementedError()
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 0cab10fc3..057371d40 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -2,6 +2,7 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2011 Justin Santa Barbara
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -51,6 +52,7 @@ from nova import manager
from nova import rpc
from nova import utils
from nova.compute import power_state
+from nova.compute import driver
FLAGS = flags.FLAGS
flags.DEFINE_string('instances_path', '$state_path/instances',
@@ -115,7 +117,9 @@ class ComputeManager(manager.Manager):
# and redocument the module docstring
if not compute_driver:
compute_driver = FLAGS.compute_driver
- self.driver = utils.import_object(compute_driver)
+ self.driver = utils.check_instance(utils.import_object(
+ compute_driver),
+ driver.ComputeDriver)
self.network_manager = utils.import_object(FLAGS.network_manager)
self.volume_manager = utils.import_object(FLAGS.volume_manager)
super(ComputeManager, self).__init__(*args, **kwargs)
@@ -974,3 +978,53 @@ class ComputeManager(manager.Manager):
for volume in instance_ref['volumes']:
self.db.volume_update(ctxt, volume['id'], {'status': 'in-use'})
+
+ def periodic_tasks(self, context=None):
+ """Tasks to be run at a periodic interval."""
+ super(ComputeManager, self).periodic_tasks(context)
+ try:
+ self._poll_instance_states(context)
+ except Exception as ex:
+ LOG.warning(_("Error during instance poll: %s"),
+ unicode(ex))
+
+ def _poll_instance_states(self, context):
+ vm_instances = self.driver.list_instances_detail(context)
+ vm_instances = dict((vm.name, vm) for vm in vm_instances)
+
+ # Keep a list of VMs not in the DB, cross them off as we find them
+ vms_not_found_in_db = [vm.name for vm in vm_instances]
+
+ db_instances = self.db.instance_get_all_by_host(context, self.host)
+ for db_instance in db_instances:
+ name = db_instance['name']
+ vm_instance = vm_instances.get(name)
+ if vm_instance is None:
+ LOG.info(_("Found instance '%(name)' in DB but no VM. "
+ "Shutting off.") % locals())
+ vm_state = power_state.SHUTOFF
+ else:
+ vm_state = vm_instance.state
+ vms_not_found_in_db.remove(name)
+
+ db_state = db_instance['state']
+ if vm_state != db_state:
+ LOG.info(_("DB/VM state mismatch. Changing state from "
+ "%(db_state) to %(vm_state)") % locals())
+ self.db.instance_set_state(context,
+ db_instance['id'],
+ vm_state)
+
+ if vm_state == power_state.SHUTOFF:
+ # TODO(soren): This is what the compute manager does when you
+ # terminate an instance. At some point I figure we'll have a
+ # "terminated" state and some sort of cleanup job that runs
+ # occasionally, cleaning them out.
+ self.db.instance_destroy(context, db_instance['id'])
+
+ # Are there VMs not in the DB?
+ for vm_not_found_in_db in vms_not_found_in_db:
+ name = vm_not_found_in_db
+ #TODO(justinsb): What to do here? Adopt it? Shut it down?
+ LOG.warning(_("Found VM not in DB: %(name). Ignoring")
+ % locals())
diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py
index adfc2dff0..145362f97 100644
--- a/nova/compute/power_state.py
+++ b/nova/compute/power_state.py
@@ -2,6 +2,7 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2011 Justin Santa Barbara
# All Rights Reserved.
# Copyright (c) 2010 Citrix Systems, Inc.
#
@@ -19,6 +20,7 @@
"""The various power states that a VM can be in."""
+#NOTE(justinsb): These are the virDomainState values from libvirt
NOSTATE = 0x00
RUNNING = 0x01
BLOCKED = 0x02
@@ -29,9 +31,8 @@ CRASHED = 0x06
SUSPENDED = 0x07
FAILED = 0x08
-
-def name(code):
- d = {
+#TODO(justinsb): Power state really needs to be a proper class...
+_STATE_MAP = {
NOSTATE: 'pending',
RUNNING: 'running',
BLOCKED: 'blocked',
@@ -41,4 +42,11 @@ def name(code):
CRASHED: 'crashed',
SUSPENDED: 'suspended',
FAILED: 'failed to spawn'}
- return d[code]
+
+
+def name(code):
+ return _STATE_MAP[code]
+
+
+def valid_states():
+ return _STATE_MAP.values()
diff --git a/nova/utils.py b/nova/utils.py
index 87e726394..e93f489be 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -585,3 +585,12 @@ def get_from_path(items, path):
return results
else:
return get_from_path(results, remainder)
+
+
+def check_instance(obj, cls):
+ """Checks that obj is of type cls, and lets PyLint infer types"""
+ if isinstance(obj, cls):
+ return obj
+ raise Exception(_("Expected object of type: %s") % (str(cls)))
+ #TODO(justinsb): Can we make this better??
+ return cls() # Ugly PyLint hack
diff --git a/nova/virt/connection.py b/nova/virt/connection.py
index 13181b730..d585b6c21 100644
--- a/nova/virt/connection.py
+++ b/nova/virt/connection.py
@@ -23,6 +23,8 @@ import sys
from nova import flags
from nova import log as logging
+from nova import utils
+from nova.compute import driver
from nova.virt import fake
from nova.virt import libvirt_conn
from nova.virt import xenapi_conn
@@ -72,4 +74,4 @@ def get_connection(read_only=False):
if conn is None:
LOG.error(_('Failed to open connection to the hypervisor'))
sys.exit(1)
- return conn
+ return utils.check_instance(conn, driver.ComputeDriver)
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 3a06284a1..18cca3f5e 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -26,6 +26,8 @@ semantics of real hypervisor connections.
"""
from nova import exception
+from nova import utils
+from nova.compute import driver
from nova.compute import power_state
@@ -34,7 +36,14 @@ def get_connection(_):
return FakeConnection.instance()
-class FakeConnection(object):
+class FakeInstance(object):
+
+ def __init__(self, name, state):
+ self.name = name
+ self.state = state
+
+
+class FakeConnection(driver.ComputeDriver):
"""
The interface to this class talks in terms of 'instances' (Amazon EC2 and
internal Nova terminology), by which we mean 'running virtual machine'
@@ -90,6 +99,17 @@ class FakeConnection(object):
"""
return self.instances.keys()
+ def _map_to_instance_info(self, instance):
+ instance = utils.check_instance(instance, FakeInstance)
+ info = driver.InstanceInfo(instance.name, instance.state)
+ return info
+
+ def list_instances_detail(self):
+ info_list = []
+ for instance in self.instances:
+ info_list.append(self._map_to_instance_info(instance))
+ return info_list
+
def spawn(self, instance):
"""
Create a new instance/VM/domain on the virtualization platform.
@@ -109,9 +129,10 @@ class FakeConnection(object):
that it was before this call began.
"""
- fake_instance = FakeInstance()
- self.instances[instance.name] = fake_instance
- fake_instance._state = power_state.RUNNING
+ name = instance.name
+ state = power_state.RUNNING
+ fake_instance = FakeInstance(name, state)
+ self.instances[name] = fake_instance
def snapshot(self, instance, name):
"""
@@ -270,7 +291,7 @@ class FakeConnection(object):
raise exception.NotFound(_("Instance %s Not Found")
% instance_name)
i = self.instances[instance_name]
- return {'state': i._state,
+ return {'state': i.state,
'max_mem': 0,
'mem': 0,
'num_cpu': 2,
@@ -428,8 +449,3 @@ class FakeConnection(object):
"""This method is supported only by libvirt."""
raise NotImplementedError('This method is supported only by libvirt.')
-
-class FakeInstance(object):
-
- def __init__(self):
- self._state = power_state.NOSTATE
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index 29d18dac5..aea7413c6 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -67,6 +67,7 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova.auth import manager
+from nova.compute import driver
from nova.compute import power_state
from nova.virt import images
@@ -108,8 +109,9 @@ def get_connection(_):
return HyperVConnection()
-class HyperVConnection(object):
+class HyperVConnection(driver.ComputeDriver):
def __init__(self):
+ super(HyperVConnection, self).__init__()
self._conn = wmi.WMI(moniker='//./root/virtualization')
self._cim_conn = wmi.WMI(moniker='//./root/cimv2')
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 0b306c950..e95bcac39 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -60,6 +60,7 @@ from nova import log as logging
#from nova import test
from nova import utils
from nova.auth import manager
+from nova.compute import driver
from nova.compute import instance_types
from nova.compute import power_state
from nova.virt import disk
@@ -154,9 +155,10 @@ def _get_ip_version(cidr):
return int(net.version())
-class LibvirtConnection(object):
+class LibvirtConnection(driver.ComputeDriver):
def __init__(self, read_only):
+ super(LibvirtConnection, self).__init__()
self.libvirt_uri = self.get_uri()
self.libvirt_xml = open(FLAGS.libvirt_xml_template).read()
@@ -235,6 +237,26 @@ class LibvirtConnection(object):
return [self._conn.lookupByID(x).name()
for x in self._conn.listDomainsID()]
+ def _map_to_instance_info(self, domain):
+ # .info() returns a list of:
+ #state: one of the state values (virDomainState)
+ #maxMemory: the maximum memory used by the domain
+ #memory: the current amount of memory used by the domain
+ #nbVirtCPU: the number of virtual CPU
+ #cpuTime: the time used by the domain in nanoseconds
+ (state, _max_mem, _mem, _num_cpu, _cpu_time) = domain.info()
+ name = domain.name()
+
+ return driver.InstanceInfo(name, state)
+
+ def list_instances_detail(self):
+ infos = []
+ for domain_id in self._conn.listDomainsID():
+ domain = self._conn.lookupById(domain_id)
+ info = self._map_to_instance_info(domain)
+ infos.append(info)
+ return infos
+
def destroy(self, instance, cleanup=True):
try:
virt_dom = self._conn.lookupByName(instance['name'])
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index fcb290d03..2fce93e38 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -34,6 +34,7 @@ from nova import exception
from nova import utils
from nova.auth.manager import AuthManager
+from nova.compute import driver
from nova.compute import power_state
from nova.virt.xenapi.network_utils import NetworkHelper
from nova.virt.xenapi.vm_utils import VMHelper
@@ -55,6 +56,8 @@ class VMOps(object):
def list_instances(self):
"""List VM instances"""
+ # TODO(justinsb): Should we just always use the details method?
+ # Seems to be the same number of API calls..
vm_refs = []
for vm_ref in self._session.get_xenapi().VM.get_all():
vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
@@ -62,6 +65,22 @@ class VMOps(object):
vm_refs.append(vm_rec["name_label"])
return vm_refs
+ def list_instances_detail(self):
+ """List VM instances, returning InstanceInfo objects"""
+ instance_infos = []
+ for vm_ref in self._session.get_xenapi().VM.get_all():
+ vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
+ if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]:
+ name = vm_rec["name_label"]
+
+ #TODO(justinsb): Yuk...
+ openstack_format = VMHelper.compile_info(vm_rec)
+ state = openstack_format['state']
+
+ instance_info = driver.InstanceInfo(name, state)
+ instance_infos.append(instance_info)
+ return instance_infos
+
def _start(self, instance, vm_ref=None):
"""Power on a VM instance"""
if not vm_ref:
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index da42a83b6..9390db0bb 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -69,6 +69,7 @@ from nova import db
from nova import utils
from nova import flags
from nova import log as logging
+from nova.compute import driver
from nova.virt.xenapi.vmops import VMOps
from nova.virt.xenapi.volumeops import VolumeOps
@@ -141,10 +142,11 @@ def get_connection(_):
return XenAPIConnection(url, username, password)
-class XenAPIConnection(object):
+class XenAPIConnection(driver.ComputeDriver):
"""A connection to XenServer or Xen Cloud Platform"""
def __init__(self, url, user, pw):
+ super(XenAPIConnection, self).__init__()
session = XenAPISession(url, user, pw)
self._vmops = VMOps(session)
self._volumeops = VolumeOps(session)
@@ -160,6 +162,9 @@ class XenAPIConnection(object):
"""List VM instances"""
return self._vmops.list_instances()
+ def list_instances_detail(self):
+ return self._vmops.list_instances_detail()
+
def spawn(self, instance):
"""Create VM instance"""
self._vmops.spawn(instance)
--
cgit
From 54f16ee6012082c1ad9de423698573c5d9b47540 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 14:38:39 -0700
Subject: pep8
---
nova/virt/fake.py | 1 -
nova/virt/xenapi/vmops.py | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 18cca3f5e..ccf2a7d68 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -448,4 +448,3 @@ class FakeConnection(driver.ComputeDriver):
def unfilter_instance(self, instance_ref):
"""This method is supported only by libvirt."""
raise NotImplementedError('This method is supported only by libvirt.')
-
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 2fce93e38..3a58a887e 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -72,7 +72,7 @@ class VMOps(object):
vm_rec = self._session.get_xenapi().VM.get_record(vm_ref)
if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]:
name = vm_rec["name_label"]
-
+
#TODO(justinsb): Yuk...
openstack_format = VMHelper.compile_info(vm_rec)
state = openstack_format['state']
--
cgit
From 5b1422afe12d4e9b7fdfdc6a61cdcd51962dab4d Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Mon, 14 Mar 2011 14:43:53 -0700
Subject: Fix for LP Bug #704300
---
nova/virt/libvirt_conn.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 0b306c950..e0222956e 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -339,7 +339,11 @@ class LibvirtConnection(object):
def reboot(self, instance):
self.destroy(instance, False)
xml = self.to_xml(instance)
+ self.firewall_driver.setup_basic_filtering(instance)
+ self.firewall_driver.prepare_instance_filter(instance)
self._conn.createXML(xml, 0)
+ self.firewall_driver.apply_instance_filter(instance)
+
timer = utils.LoopingCall(f=None)
def _wait_for_reboot():
--
cgit
From 738653b6b4ac744519a050fe50e7c795a7c63579 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 15:11:14 -0700
Subject: Added test and fixed up code so that it works
---
nova/compute/manager.py | 16 +++++++++++-----
nova/tests/test_compute.py | 21 +++++++++++++++++++++
nova/virt/fake.py | 6 +++++-
3 files changed, 37 insertions(+), 6 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 057371d40..a7727a239 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -981,26 +981,32 @@ class ComputeManager(manager.Manager):
def periodic_tasks(self, context=None):
"""Tasks to be run at a periodic interval."""
- super(ComputeManager, self).periodic_tasks(context)
+ error_list = super(ComputeManager, self).periodic_tasks(context)
+ if error_list is None:
+ error_list = []
+
try:
self._poll_instance_states(context)
except Exception as ex:
LOG.warning(_("Error during instance poll: %s"),
unicode(ex))
+ error_list.append(ex)
+ return error_list
def _poll_instance_states(self, context):
- vm_instances = self.driver.list_instances_detail(context)
+ vm_instances = self.driver.list_instances_detail()
vm_instances = dict((vm.name, vm) for vm in vm_instances)
# Keep a list of VMs not in the DB, cross them off as we find them
vms_not_found_in_db = [vm.name for vm in vm_instances]
db_instances = self.db.instance_get_all_by_host(context, self.host)
+
for db_instance in db_instances:
name = db_instance['name']
vm_instance = vm_instances.get(name)
if vm_instance is None:
- LOG.info(_("Found instance '%(name)' in DB but no VM. "
+ LOG.info(_("Found instance '%(name)s' in DB but no VM. "
"Shutting off.") % locals())
vm_state = power_state.SHUTOFF
else:
@@ -1010,7 +1016,7 @@ class ComputeManager(manager.Manager):
db_state = db_instance['state']
if vm_state != db_state:
LOG.info(_("DB/VM state mismatch. Changing state from "
- "%(db_state) to %(vm_state)") % locals())
+ "'%(db_state)s' to '%(vm_state)s'") % locals())
self.db.instance_set_state(context,
db_instance['id'],
vm_state)
@@ -1026,5 +1032,5 @@ class ComputeManager(manager.Manager):
for vm_not_found_in_db in vms_not_found_in_db:
name = vm_not_found_in_db
#TODO(justinsb): What to do here? Adopt it? Shut it down?
- LOG.warning(_("Found VM not in DB: %(name). Ignoring")
+ LOG.warning(_("Found VM not in DB: '%(name)s'. Ignoring")
% locals())
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index e486050be..b9d0aa0b6 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -595,3 +595,24 @@ class ComputeTestCase(test.TestCase):
db.instance_destroy(c, instance_id)
db.volume_destroy(c, v_ref['id'])
db.floating_ip_destroy(c, flo_addr)
+
+ def test_run_kill_vm(self):
+ """Detect when a vm is terminated behind the scenes"""
+ instance_id = self._create_instance()
+
+ self.compute.run_instance(self.context, instance_id)
+
+ instances = db.instance_get_all(context.get_admin_context())
+ LOG.info(_("Running instances: %s"), instances)
+ self.assertEqual(len(instances), 1)
+
+ instance_name = instances[0].name
+ self.compute.driver.test_remove_vm(instance_name)
+
+ # Force the compute manager to do its periodic poll
+ error_list = self.compute.periodic_tasks(context.get_admin_context())
+ self.assertFalse(error_list)
+
+ instances = db.instance_get_all(context.get_admin_context())
+ LOG.info(_("After force-killing instances: %s"), instances)
+ self.assertEqual(len(instances), 0)
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index ccf2a7d68..e0e2369c7 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -106,7 +106,7 @@ class FakeConnection(driver.ComputeDriver):
def list_instances_detail(self):
info_list = []
- for instance in self.instances:
+ for instance in self.instances.values():
info_list.append(self._map_to_instance_info(instance))
return info_list
@@ -448,3 +448,7 @@ class FakeConnection(driver.ComputeDriver):
def unfilter_instance(self, instance_ref):
"""This method is supported only by libvirt."""
raise NotImplementedError('This method is supported only by libvirt.')
+
+ def test_remove_vm(self, instance_name):
+ """ Removes the named VM, as if it crashed. For testing"""
+ self.instances.pop(instance_name)
--
cgit
From 9f135cc4d6069a0b882c8e848d3b6cb292002d10 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 15:37:04 -0700
Subject: Implemented Hyper-V list_instances_detail function. Needs a cleanup
by someone that knows the Hyper-V code
---
nova/virt/hyperv.py | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index aea7413c6..435272109 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -126,6 +126,19 @@ class HyperVConnection(driver.ComputeDriver):
for v in self._conn.Msvm_ComputerSystem(['ElementName'])]
return vms
+ def list_instances_detail(self):
+ #TODO(justinsb): This is a terrible implementation (1+N)
+ instance_infos = []
+ for instance_name in self.list_instances():
+ info = self.get_info(instance_name)
+
+ state = info['state']
+
+ instance_info = driver.InstanceInfo(instance_name, state)
+ instance_infos.append(instance_info)
+
+ return instance_infos
+
def spawn(self, instance):
""" Create a new VM and start it."""
vm = self._lookup(instance.name)
@@ -347,7 +360,7 @@ class HyperVConnection(driver.ComputeDriver):
newinst = cl.new()
#Copy the properties from the original.
for prop in wmi_obj._properties:
- newinst.Properties_.Item(prop).Value =\
+ newinst.Properties_.Item(prop).Value = \
wmi_obj.Properties_.Item(prop).Value
return newinst
--
cgit
From 9dce9ee5fe5a1df018b9a606a3ea35b2dbfc987e Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 15:37:29 -0700
Subject: Clarified message when a VM is not running but still in DB
---
nova/compute/manager.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index a7727a239..019bb3c89 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1007,7 +1007,7 @@ class ComputeManager(manager.Manager):
vm_instance = vm_instances.get(name)
if vm_instance is None:
LOG.info(_("Found instance '%(name)s' in DB but no VM. "
- "Shutting off.") % locals())
+ "Setting state to shutoff.") % locals())
vm_state = power_state.SHUTOFF
else:
vm_state = vm_instance.state
--
cgit
From 2b20306fcaddcb6b9bc57fb55b17230d709cd1ce Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 22:23:38 -0700
Subject: Derive unit test from standard nova.test.TestCase
---
nova/tests/integrated/test_login.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
index e362f92d6..5fa558bdf 100644
--- a/nova/tests/integrated/test_login.py
+++ b/nova/tests/integrated/test_login.py
@@ -18,6 +18,7 @@
import unittest
from nova import flags
+from nova import test
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
@@ -29,7 +30,7 @@ FLAGS = flags.FLAGS
FLAGS.verbose = True
-class LoginTest(unittest.TestCase):
+class LoginTest(test.TestCase):
def setUp(self):
super(LoginTest, self).setUp()
context = integrated_helpers.IntegratedUnitTestContext.startup()
@@ -73,5 +74,6 @@ class LoginTest(unittest.TestCase):
self.assertRaises(client.OpenstackApiAuthenticationException,
bad_credentials_api.get_flavors)
+
if __name__ == "__main__":
unittest.main()
--
cgit
From db8beffc9acd90c748512c1fa9c127d39756232c Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 22:36:30 -0700
Subject: Reapplied rename of Openstack -> OpenStack. Easier to do it by hand
than to ask Bazaar to do it.
---
nova/tests/integrated/api/client.py | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index 6fba2930a..568e8c17e 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -24,7 +24,7 @@ from nova import log as logging
LOG = logging.getLogger('nova.tests.api')
-class OpenstackApiException(Exception):
+class OpenStackApiException(Exception):
def __init__(self, message=None, response=None):
self.response = response
if not message:
@@ -37,22 +37,22 @@ class OpenstackApiException(Exception):
message = _('%(message)s\nStatus Code: %(_status)s\n'
'Body: %(_body)s') % locals()
- super(OpenstackApiException, self).__init__(message)
+ super(OpenStackApiException, self).__init__(message)
-class OpenstackApiAuthenticationException(OpenstackApiException):
+class OpenStackApiAuthenticationException(OpenStackApiException):
def __init__(self, response=None, message=None):
if not message:
message = _("Authentication error")
- super(OpenstackApiAuthenticationException, self).__init__(message,
+ super(OpenStackApiAuthenticationException, self).__init__(message,
response)
-class OpenstackApiNotFoundException(OpenstackApiException):
+class OpenStackApiNotFoundException(OpenStackApiException):
def __init__(self, response=None, message=None):
if not message:
message = _("Item not found")
- super(OpenstackApiNotFoundException, self).__init__(message, response)
+ super(OpenStackApiNotFoundException, self).__init__(message, response)
class TestOpenStackClient(object):
@@ -82,7 +82,7 @@ class TestOpenStackClient(object):
conn = httplib.HTTPSConnection(hostname,
port=port)
else:
- raise OpenstackApiException("Unknown scheme: %s" % url)
+ raise OpenStackApiException("Unknown scheme: %s" % url)
relative_url = parsed_url.path
if parsed_url.query:
@@ -112,7 +112,7 @@ class TestOpenStackClient(object):
# bug732866
#if http_status == 401:
if http_status != 204:
- raise OpenstackApiAuthenticationException(response=response)
+ raise OpenStackApiAuthenticationException(response=response)
auth_headers = {}
for k, v in response.getheaders():
@@ -139,9 +139,9 @@ class TestOpenStackClient(object):
if check_response_status:
if not http_status in check_response_status:
if http_status == 404:
- raise OpenstackApiNotFoundException(response=response)
+ raise OpenStackApiNotFoundException(response=response)
else:
- raise OpenstackApiException(
+ raise OpenStackApiException(
message=_("Unexpected status code"),
response=response)
--
cgit
From e0563f49792441af106c52e662bdada3c7997feb Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Mon, 14 Mar 2011 22:43:21 -0700
Subject: Reapplied rename to another file.
---
nova/tests/integrated/test_login.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/tests/integrated/test_login.py b/nova/tests/integrated/test_login.py
index 5fa558bdf..501f8c919 100644
--- a/nova/tests/integrated/test_login.py
+++ b/nova/tests/integrated/test_login.py
@@ -53,7 +53,7 @@ class LoginTest(test.TestCase):
"notso_password",
self.user.auth_url)
- self.assertRaises(client.OpenstackApiAuthenticationException,
+ self.assertRaises(client.OpenStackApiAuthenticationException,
bad_credentials_api.get_flavors)
def test_bad_login_username(self):
@@ -62,7 +62,7 @@ class LoginTest(test.TestCase):
self.user.secret,
self.user.auth_url)
- self.assertRaises(client.OpenstackApiAuthenticationException,
+ self.assertRaises(client.OpenStackApiAuthenticationException,
bad_credentials_api.get_flavors)
def test_bad_login_both_bad(self):
@@ -71,7 +71,7 @@ class LoginTest(test.TestCase):
"notso_password",
self.user.auth_url)
- self.assertRaises(client.OpenstackApiAuthenticationException,
+ self.assertRaises(client.OpenStackApiAuthenticationException,
bad_credentials_api.get_flavors)
--
cgit
From f1acc3d199a1a92b531a3e74ed54a8b2fcdb999c Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 15 Mar 2011 13:52:03 -0700
Subject: Now that the fix for 732866, stop working around the bug
---
nova/tests/integrated/api/client.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index 568e8c17e..fc7c344e7 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -108,10 +108,7 @@ class TestOpenStackClient(object):
http_status = response.status
LOG.debug(_("%(auth_uri)s => code %(http_status)s") % locals())
- # Until bug732866 is fixed, we can't check this properly...
- # bug732866
- #if http_status == 401:
- if http_status != 204:
+ if http_status == 401:
raise OpenStackApiAuthenticationException(response=response)
auth_headers = {}
--
cgit
From 67c871a257c684de3cb0f1416b1b2b6e9a99fe23 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Tue, 15 Mar 2011 17:37:07 -0500
Subject: Moving the migration again
---
.../versions/011_add_flavors_to_migrations.py | 44 ----------------------
.../versions/012_add_flavors_to_migrations.py | 44 ++++++++++++++++++++++
2 files changed, 44 insertions(+), 44 deletions(-)
delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py
create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py
deleted file mode 100644
index 412caedd0..000000000
--- a/nova/db/sqlalchemy/migrate_repo/versions/011_add_flavors_to_migrations.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 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.from sqlalchemy import *
-
-from sqlalchemy import *
-from migrate import *
-
-from nova import log as logging
-
-
-meta = MetaData()
-
-migrations = Table('migrations', meta,
- Column('id', Integer(), primary_key=True, nullable=False),
- )
-
-#
-# Tables to alter
-#
-#
-
-old_flavor_id = Column('old_flavor_id', Integer())
-new_flavor_id = Column('new_flavor_id', Integer())
-
-
-def upgrade(migrate_engine):
- # Upgrade operations go here. Don't create your own engine;
- # bind migrate_engine to your metadata
- meta.bind = migrate_engine
- migrations.create_column(old_flavor_id)
- migrations.create_column(new_flavor_id)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
new file mode 100644
index 000000000..412caedd0
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
@@ -0,0 +1,44 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 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.from sqlalchemy import *
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+migrations = Table('migrations', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+#
+# Tables to alter
+#
+#
+
+old_flavor_id = Column('old_flavor_id', Integer())
+new_flavor_id = Column('new_flavor_id', Integer())
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+ migrations.create_column(old_flavor_id)
+ migrations.create_column(new_flavor_id)
--
cgit
From 74987666f89b4d15ffcf17b43b3752135ba08a65 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Tue, 15 Mar 2011 18:48:17 -0500
Subject: A few fixes
---
nova/compute/manager.py | 2 +-
nova/virt/xenapi/vmops.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 39b28f6a9..307c91650 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -541,7 +541,7 @@ class ComputeManager(manager.Manager):
#after they're supported
instance_type = self.db.instance_type_get_by_flavor_id(context,
migration_ref['new_flavor_id'])
- self.db.instance_update(context, instance_ref,
+ self.db.instance_update(context, instance_id,
dict(memory_mb=instance_type['memory_mb'],
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index d1aaf998f..119d6dba8 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -304,7 +304,7 @@ class VMOps(object):
try:
# transfer the base copy
template_vm_ref, template_vdi_uuids = self._get_snapshot(instance)
- base_copy_uuid = template_vdi_uuids[1]
+ base_copy_uuid = template_vdi_uuids['snap']
vdi_ref, vm_vdi_rec = \
VMHelper.get_vdi_for_vm_safely(self._session, vm_ref)
cow_uuid = vm_vdi_rec['uuid']
@@ -319,7 +319,7 @@ class VMOps(object):
self._session.wait_for_task(task, instance.id)
# Now power down the instance and transfer the COW VHD
- self._shutdown(instance, vm_ref, method='clean')
+ self._shutdown(instance, vm_ref)
params = {'host': dest,
'vdi_uuid': cow_uuid,
--
cgit
From 39e722b58b87297aee770637f6a82ee1f206aecf Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Tue, 15 Mar 2011 18:51:22 -0500
Subject: Tweak
---
nova/virt/xenapi/vmops.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 119d6dba8..958201695 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -319,7 +319,7 @@ class VMOps(object):
self._session.wait_for_task(task, instance.id)
# Now power down the instance and transfer the COW VHD
- self._shutdown(instance, vm_ref)
+ self._shutdown(instance, vm_ref, hard=False)
params = {'host': dest,
'vdi_uuid': cow_uuid,
@@ -447,7 +447,8 @@ class VMOps(object):
"""Shutdown an instance"""
state = self.get_info(instance['name'])['state']
if state == power_state.SHUTDOWN:
- LOG.warn(_("VM %(vm)s already halted, skipping shutdown...") %
+ instance_name = instance.name
+ LOG.warn(_("VM %(instance_name)s already halted, skipping shutdown...") %
locals())
return
--
cgit
From 9650e73db3e18f839f8abf7a47aebb6fbf8c9e36 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Tue, 15 Mar 2011 19:10:50 -0500
Subject: Plugin
---
nova/virt/xenapi/vmops.py | 1 -
plugins/xenserver/xenapi/etc/xapi.d/plugins/migration | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 958201695..cdc4a417c 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -370,7 +370,6 @@ class VMOps(object):
#TODO(mdietz): this will need to be adjusted for swap later
task = self._session.call_xenapi('VDI.resize_online', vdi_ref,
new_disk_size)
- vm_ref = VMHelper.lookup(self._session, instance.name)
self._session.wait_for_task(task, instance.id)
def reboot(self, instance):
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
index 4aa89863a..6008e71bf 100644
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
@@ -22,6 +22,7 @@ XenAPI Plugin for transfering data between host nodes
import os
import os.path
import pickle
+import shlex
import shutil
import subprocess
--
cgit
From e2f8c143eab3b43acd9e3658a480f75f435e7d42 Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 16 Mar 2011 19:51:06 +0900
Subject: Updating gateway_v6 in _on_set_network_host() is not required for
FlatManager
---
nova/network/manager.py | 5 -----
1 file changed, 5 deletions(-)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index c51eb9ad0..7e28e6da2 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -404,11 +404,6 @@ class FlatManager(NetworkManager):
net = {}
net['injected'] = FLAGS.flat_injected
net['dns'] = FLAGS.flat_network_dns
- if not FLAGS.fake_network:
- if(FLAGS.use_ipv6):
- net['gateway_v6'] = \
- utils.get_my_linklocal(
- FLAGS.flat_network_bridge)
self.db.network_update(context, network_id, net)
def allocate_floating_ip(self, context, project_id):
--
cgit
From 8964cbecc10885bc6eff08544d62db1747fb14ef Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 16 Mar 2011 20:24:20 +0900
Subject: pep8 clean
---
nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index be1edc8f6..9f98f436f 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -83,8 +83,7 @@ networks = Table('networks', meta,
Column(
'label',
String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
- )
+ unicode_error=None, _warn_on_bytestring=False)))
fixed_ips = Table('fixed_ips', meta,
Column('created_at', DateTime(timezone=False)),
--
cgit
From 2e81ce6bb5b1083220e7ae5c17113fd44465ddbf Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 16 Mar 2011 21:17:19 +0900
Subject: Fix instance creation fail under use_ipv6=false and FlatManager
---
nova/virt/libvirt_conn.py | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 9efbb3342..a850bad87 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -660,11 +660,10 @@ class LibvirtConnection(object):
if network_ref['injected']:
admin_context = context.get_admin_context()
address = db.instance_get_fixed_address(admin_context, inst['id'])
- address_v6 = db.instance_get_fixed_address_v6(admin_context,
- inst['id'])
- gateway_v6 = network_ref['gateway_v6']
- if not gateway_v6:
- gateway_v6 = "fd00::"
+ address_v6 = None
+ if FLAGS.use_ipv6:
+ address_v6 = db.instance_get_fixed_address_v6(admin_context,
+ inst['id'])
interfaces_info = {'address': address,
'netmask': network_ref['netmask'],
--
cgit
From d1469d1566a67d41cb4de4ff06deaf441e099062 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 11:26:40 -0500
Subject: Some typos
---
nova/compute/api.py | 4 +++-
plugins/xenserver/xenapi/etc/xapi.d/plugins/migration | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 0e9bf2424..08947eb3a 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -443,6 +443,8 @@ class API(base.Base):
params = {'migration_id': migration_ref['id']}
self._cast_compute_message('revert_resize', context, instance_id,
migration_ref['dest_compute'], params=params)
+ self.db.migration_update(context, migration_ref['id'],
+ {'status': 'reverted'})
def confirm_resize(self, context, instance_id):
"""Confirms a migration/resize, deleting the 'old' instance in the
@@ -458,7 +460,7 @@ class API(base.Base):
self._cast_compute_message('confirm_resize', context, instance_id,
migration_ref['source_compute'], params=params)
- self.db.migration_update(context, migration_id,
+ self.db.migration_update(context, migration_ref['id'],
{'status': 'confirmed'})
self.db.instance_update(context, instance_id,
{'host': migration_ref['dest_compute'], })
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
index 6008e71bf..75c653408 100644
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration
@@ -98,7 +98,7 @@ def transfer_vhd(session, args):
logging.debug("Preparing to transmit %s to %s" % (source_path,
dest_path))
- ssh_cmd = 'ssh -o StrictHostKeyChecking=no'
+ ssh_cmd = '\"ssh -o StrictHostKeyChecking=no\"'
rsync_args = shlex.split('nohup /usr/bin/rsync -av --progress -e %s %s %s'
% (ssh_cmd, source_path, dest_path))
--
cgit
From 9cb503ae9d4112fa464f2284631ad1e24f8f7ce4 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 11:38:40 -0500
Subject: Stuff
---
nova/virt/xenapi/vmops.py | 3 +--
nova/virt/xenapi_conn.py | 6 +-----
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index cdc4a417c..ebaa4a69a 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -363,8 +363,7 @@ class VMOps(object):
def resize_instance(self, instance, vdi_uuid):
"""Resize a running instance by changing it's RAM and disk size """
vm_ref = VMHelper.lookup(self._session, instance.name)
- vdi_ref, vm_vdi_rec = \
- VMHelper.get_vdi_for_vm_safely(self._session, vm_ref)
+ vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
new_disk_size = instance.local_gb
#TODO(mdietz): this will need to be adjusted for swap later
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 6b1b51fee..b8256d205 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -164,15 +164,11 @@ class XenAPIConnection(object):
"""Create VM instance"""
self._vmops.spawn(instance)
- def resize_instance(self, instance, disk_info):
- """Resizes instance attributes such as RAM and disk space to the
- attributes specified by the record"""
- self._vmops.resize_instance(instance, disk_info['cow'])
-
def finish_resize(self, instance, disk_info):
"""Completes a resize, turning on the migrated instance"""
vdi_uuid = self._vmops.attach_disk(instance, disk_info['base_copy'],
disk_info['cow'])
+ self._vmops.resize_instance(instance, vdi_uuid)
self._vmops._spawn_with_disk(instance, vdi_uuid)
def snapshot(self, instance, image_id):
--
cgit
From dee86f53b0d1dccbc69d354b66ca7a4767e81d43 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 11:54:10 -0500
Subject: tweak
---
nova/compute/manager.py | 1 -
nova/virt/xenapi/vmops.py | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 307c91650..1587660a3 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -546,7 +546,6 @@ class ComputeManager(manager.Manager):
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
- self.driver.resize_instance(instance_ref, disk_info)
self.driver.finish_resize(instance_ref, disk_info)
self.db.migration_update(context, migration_id,
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index ebaa4a69a..483b0cb82 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -364,7 +364,7 @@ class VMOps(object):
"""Resize a running instance by changing it's RAM and disk size """
vm_ref = VMHelper.lookup(self._session, instance.name)
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
- new_disk_size = instance.local_gb
+ new_disk_size = instance.local_gb * 1024
#TODO(mdietz): this will need to be adjusted for swap later
task = self._session.call_xenapi('VDI.resize_online', vdi_ref,
--
cgit
From d99a8d48cf38eb6be01587f9b377f48ff6cd88a2 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Wed, 16 Mar 2011 17:09:13 +0000
Subject: Logging statements
---
nova/virt/xenapi/vmops.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 483b0cb82..c292822ca 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -363,13 +363,16 @@ class VMOps(object):
def resize_instance(self, instance, vdi_uuid):
"""Resize a running instance by changing it's RAM and disk size """
vm_ref = VMHelper.lookup(self._session, instance.name)
- vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
new_disk_size = instance.local_gb * 1024
+ LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %d megs") % (vdi_uuid,
+ instance.name, new_disk_size))
+ vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
#TODO(mdietz): this will need to be adjusted for swap later
task = self._session.call_xenapi('VDI.resize_online', vdi_ref,
new_disk_size)
self._session.wait_for_task(task, instance.id)
+ LOG.debug(_("Resize instance %s complete") % (instance.name))
def reboot(self, instance):
"""Reboot VM instance"""
--
cgit
From a31e715617e5af107bc79caeedf0aff41f65fb07 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 12:57:45 -0500
Subject: The geebees
---
nova/virt/xenapi/vmops.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index c292822ca..b449437c9 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -363,7 +363,7 @@ class VMOps(object):
def resize_instance(self, instance, vdi_uuid):
"""Resize a running instance by changing it's RAM and disk size """
vm_ref = VMHelper.lookup(self._session, instance.name)
- new_disk_size = instance.local_gb * 1024
+ new_disk_size = str(instance.local_gb * 1024 * 1024)
LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %d megs") % (vdi_uuid,
instance.name, new_disk_size))
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
--
cgit
From e2399c434386a31114273f2cf6f14586a25480c2 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 13:06:49 -0500
Subject: Derped again
---
nova/virt/xenapi/vmops.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index b449437c9..7f80de8a9 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -363,8 +363,10 @@ class VMOps(object):
def resize_instance(self, instance, vdi_uuid):
"""Resize a running instance by changing it's RAM and disk size """
vm_ref = VMHelper.lookup(self._session, instance.name)
- new_disk_size = str(instance.local_gb * 1024 * 1024)
- LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %d megs") % (vdi_uuid,
+
+ #The new disk size must be in bytes
+ new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
+ LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %s megs") % (vdi_uuid,
instance.name, new_disk_size))
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
--
cgit
From 647f5f0d0283b3852115d821b80a965b0bc92c35 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 13:24:51 -0500
Subject: chchchchchanges
---
nova/virt/xenapi/vmops.py | 19 ++++++++++---------
nova/virt/xenapi_conn.py | 3 ++-
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 7f80de8a9..6ff0aad15 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -72,7 +72,7 @@ class VMOps(object):
LOG.debug(_("Starting instance %s"), instance.name)
self._session.call_xenapi('VM.start', vm_ref, False, False)
- def create_disk(self, instance):
+ def _create_disk(self, instance):
user = AuthManager().get_user(instance.user_id)
project = AuthManager().get_project(instance.project_id)
disk_image_type = VMHelper.determine_disk_image_type(instance)
@@ -81,11 +81,11 @@ class VMOps(object):
return vdi_uuid
def spawn(self, instance):
- vdi_uuid = self.create_disk(instance)
- self._spawn_with_disk(instance, vdi_uuid=vdi_uuid)
+ vdi_uuid = self._create_disk(instance)
+ vm_ref = self._create_vm(instance, vdi_uuid)
+ self._spawn(instance, vm_ref)
- def _spawn_with_disk(self, instance, vdi_uuid):
- """Create VM instance"""
+ def _create_vm(self, instance, vdi_uuid):
instance_name = instance.name
vm_ref = VMHelper.lookup(self._session, instance_name)
if vm_ref is not None:
@@ -130,7 +130,10 @@ class VMOps(object):
# inject_network_info and create vifs
networks = self.inject_network_info(instance)
self.create_vifs(instance, networks)
+ return vm_ref
+ def _spawn(self, instance, vm_ref):
+ """Spawn a new instance"""
LOG.debug(_('Starting VM %s...'), vm_ref)
self._start(instance, vm_ref)
LOG.info(_('Spawning VM %(instance_name)s created %(vm_ref)s.')
@@ -364,16 +367,14 @@ class VMOps(object):
"""Resize a running instance by changing it's RAM and disk size """
vm_ref = VMHelper.lookup(self._session, instance.name)
+ #TODO(mdietz): this will need to be adjusted for swap later
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %s megs") % (vdi_uuid,
instance.name, new_disk_size))
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
- #TODO(mdietz): this will need to be adjusted for swap later
- task = self._session.call_xenapi('VDI.resize_online', vdi_ref,
- new_disk_size)
- self._session.wait_for_task(task, instance.id)
+ self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
LOG.debug(_("Resize instance %s complete") % (instance.name))
def reboot(self, instance):
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index b8256d205..fd68c0fe7 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -168,8 +168,9 @@ class XenAPIConnection(object):
"""Completes a resize, turning on the migrated instance"""
vdi_uuid = self._vmops.attach_disk(instance, disk_info['base_copy'],
disk_info['cow'])
+ self._vmops._create_vm(instance, vdi_uuid)
self._vmops.resize_instance(instance, vdi_uuid)
- self._vmops._spawn_with_disk(instance, vdi_uuid)
+ self._vmops._spawn_with_disk(instance)
def snapshot(self, instance, image_id):
""" Create snapshot from a running VM instance """
--
cgit
From 11e7b6a08d1557a0986b480c032958cd30762f33 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 13:31:05 -0500
Subject: chchchchchanges
---
nova/virt/xenapi/vmops.py | 2 --
nova/virt/xenapi_conn.py | 4 ++--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 6ff0aad15..92594c9c6 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -365,8 +365,6 @@ class VMOps(object):
def resize_instance(self, instance, vdi_uuid):
"""Resize a running instance by changing it's RAM and disk size """
- vm_ref = VMHelper.lookup(self._session, instance.name)
-
#TODO(mdietz): this will need to be adjusted for swap later
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index fd68c0fe7..046f74c8d 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -168,9 +168,9 @@ class XenAPIConnection(object):
"""Completes a resize, turning on the migrated instance"""
vdi_uuid = self._vmops.attach_disk(instance, disk_info['base_copy'],
disk_info['cow'])
- self._vmops._create_vm(instance, vdi_uuid)
+ vm_ref = self._vmops._create_vm(instance, vdi_uuid)
self._vmops.resize_instance(instance, vdi_uuid)
- self._vmops._spawn_with_disk(instance)
+ self._vmops._spawn(instance, vm_ref)
def snapshot(self, instance, image_id):
""" Create snapshot from a running VM instance """
--
cgit
From d8c3ea5e6b594e6285650c5bdac6302b7be295dc Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 13:39:43 -0500
Subject: chchchchchanges
---
nova/virt/xenapi/vmops.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 92594c9c6..931fc1cb4 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -136,6 +136,7 @@ class VMOps(object):
"""Spawn a new instance"""
LOG.debug(_('Starting VM %s...'), vm_ref)
self._start(instance, vm_ref)
+ instance_name = instance.name
LOG.info(_('Spawning VM %(instance_name)s created %(vm_ref)s.')
% locals())
--
cgit
From ebd452eab95c2f205d3f7419c08c288030c38aba Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 13:53:49 -0500
Subject: chchchchchanges
---
nova/compute/manager.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 1587660a3..351e02f51 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -546,6 +546,7 @@ class ComputeManager(manager.Manager):
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
+ instance_ref = self.db.instance_get(context, instance_id)
self.driver.finish_resize(instance_ref, disk_info)
self.db.migration_update(context, migration_id,
--
cgit
From 1d4d0e26ae6ece5e68417deaa4ddcf4b7757bd37 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 14:09:14 -0500
Subject: Fudge
---
nova/compute/api.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 08947eb3a..ddf439b35 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -468,11 +468,15 @@ class API(base.Base):
def resize(self, context, instance_id, flavor_id):
"""Resize a running instance."""
instance = self.db.instance_get(context, instance_id)
+ LOG.debug(_("Resizing instance %s to flavor %d") %
+ (instance.name, flavor_id))
current_instance_type = self.db.instance_type_get_by_name(
context, instance['instance_type'])
new_instance_type = self.db.instance_type_get_by_flavor_id(
context, flavor_id)
+ LOG.debug(_("Old instance type %s -> New instance type %s") %
+ (current_instance_type['name'], new_instance_type['name']))
if not new_instance_type:
raise exception.ApiError(_("Requested flavor does not exist"))
--
cgit
From 3459cfb89bd90605e54fd1fb28b8b38089f3e236 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Wed, 16 Mar 2011 15:20:08 -0400
Subject: update image service documentation
---
nova/image/service.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/nova/image/service.py b/nova/image/service.py
index c09052cab..78d8f33e9 100644
--- a/nova/image/service.py
+++ b/nova/image/service.py
@@ -40,9 +40,9 @@ class BaseImageService(object):
:retval: a sequence of mappings with the following signature
{'id': opaque id of image,
'name': name of image,
- 'created_at': creation timestamp,
- 'updated_at': modification timestamp,
- 'deleted_at': deletion timestamp or None,
+ 'created_at': creation datetime object,
+ 'updated_at': modification datetime object,
+ 'deleted_at': deletion datetime object or None,
'deleted': boolean indicating if image has been deleted,
'status': string description of image status,
'is_public': boolean indicating if image is public
@@ -64,9 +64,9 @@ class BaseImageService(object):
{'id': opaque id of image,
'name': name of image,
- 'created_at': creation timestamp,
- 'updated_at': modification timestamp,
- 'deleted_at': deletion timestamp or None,
+ 'created_at': creation datetime object,
+ 'updated_at': modification datetime object,
+ 'deleted_at': deletion datetime object or None,
'deleted': boolean indicating if image has been deleted,
'status': string description of image status,
'is_public': boolean indicating if image is public
--
cgit
From 007c2802e542bf954f0aa5b589f2adc3a1bfa89a Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 15:41:53 -0500
Subject: Reverting
---
nova/virt/xenapi/vmops.py | 10 +++-------
nova/virt/xenapi_conn.py | 8 ++++----
2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 931fc1cb4..7525ff5ec 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -85,7 +85,8 @@ class VMOps(object):
vm_ref = self._create_vm(instance, vdi_uuid)
self._spawn(instance, vm_ref)
- def _create_vm(self, instance, vdi_uuid):
+ def _spawn(self, instance, vdi_uuid):
+ """Spawn a new instance"""
instance_name = instance.name
vm_ref = VMHelper.lookup(self._session, instance_name)
if vm_ref is not None:
@@ -130,13 +131,8 @@ class VMOps(object):
# inject_network_info and create vifs
networks = self.inject_network_info(instance)
self.create_vifs(instance, networks)
- return vm_ref
-
- def _spawn(self, instance, vm_ref):
- """Spawn a new instance"""
LOG.debug(_('Starting VM %s...'), vm_ref)
self._start(instance, vm_ref)
- instance_name = instance.name
LOG.info(_('Spawning VM %(instance_name)s created %(vm_ref)s.')
% locals())
@@ -343,7 +339,7 @@ class VMOps(object):
# sensible so we don't need to blindly pass around dictionaries
return {'base_copy': base_copy_uuid, 'cow': cow_uuid}
- def attach_disk(self, instance, base_copy_uuid, cow_uuid):
+ def link_disks(self, instance, base_copy_uuid, cow_uuid):
"""Links the base copy VHD to the COW via the XAPI plugin"""
vm_ref = VMHelper.lookup(self._session, instance.name)
new_base_copy_uuid = str(uuid.uuid4())
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 046f74c8d..99ec53c11 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -166,11 +166,11 @@ class XenAPIConnection(object):
def finish_resize(self, instance, disk_info):
"""Completes a resize, turning on the migrated instance"""
- vdi_uuid = self._vmops.attach_disk(instance, disk_info['base_copy'],
+ vdi_uuid = self._vmops.link_disks(instance, disk_info['base_copy'],
disk_info['cow'])
- vm_ref = self._vmops._create_vm(instance, vdi_uuid)
- self._vmops.resize_instance(instance, vdi_uuid)
- self._vmops._spawn(instance, vm_ref)
+ #vm_ref = self._vmops._create_vm(instance, vdi_uuid)
+ #self._vmops.resize_instance(instance, vdi_uuid)
+ self._vmops._spawn(instance, vdi_uuid)
def snapshot(self, instance, image_id):
""" Create snapshot from a running VM instance """
--
cgit
From d95187aaf144cb40558f48d584a6bb8e07c6937d Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Wed, 16 Mar 2011 14:13:57 -0700
Subject: converted new lines from CRLF to LF
---
.../versions/012_add_ipv6_flatmanager.py | 302 +++++++++----------
nova/tests/network/__init__.py | 94 +++---
nova/tests/network/base.py | 308 ++++++++++----------
nova/tests/test_flat_network.py | 322 ++++++++++-----------
4 files changed, 513 insertions(+), 513 deletions(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index 9f98f436f..5f5e3d007 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -1,151 +1,151 @@
-# Copyright 2010 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.
-
-from sqlalchemy import *
-from migrate import *
-
-from nova import log as logging
-
-
-meta = MetaData()
-
-
-# Table stub-definitions
-# Just for the ForeignKey and column creation to succeed, these are not the
-# actual definitions of instances or services.
-#
-
-#
-# Tables to alter
-#
-networks = Table('networks', meta,
- Column('created_at', DateTime(timezone=False)),
- Column('updated_at', DateTime(timezone=False)),
- Column('deleted_at', DateTime(timezone=False)),
- Column('deleted', Boolean(create_constraint=True, name=None)),
- Column('id', Integer(), primary_key=True, nullable=False),
- Column('injected', Boolean(create_constraint=True, name=None)),
- Column('cidr',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('netmask',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('bridge',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('gateway',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('broadcast',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('dns',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('vlan', Integer()),
- Column('vpn_public_address',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('vpn_public_port', Integer()),
- Column('vpn_private_address',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('dhcp_start',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('project_id',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('host',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('cidr_v6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('ra_server', String(length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- Column(
- 'label',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)))
-
-fixed_ips = Table('fixed_ips', meta,
- Column('created_at', DateTime(timezone=False)),
- Column('updated_at', DateTime(timezone=False)),
- Column('deleted_at', DateTime(timezone=False)),
- Column('deleted', Boolean(create_constraint=True, name=None)),
- Column('id', Integer(), primary_key=True, nullable=False),
- Column('address',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False)),
- Column('network_id',
- Integer(),
- ForeignKey('networks.id'),
- nullable=True),
- Column('instance_id',
- Integer(),
- ForeignKey('instances.id'),
- nullable=True),
- Column('allocated', Boolean(create_constraint=True, name=None)),
- Column('leased', Boolean(create_constraint=True, name=None)),
- Column('reserved', Boolean(create_constraint=True, name=None)),
- Column("addressV6", String(length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- Column("netmaskV6", String(length=3,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- Column("gatewayV6", String(length=255,
- convert_unicode=False,
- assert_unicode=None,
- unicode_error=None,
- _warn_on_bytestring=False)),
- )
-#
-# New Tables
-#
-# None
-
-#
-# Columns to add to existing tables
-#
-networks_netmask_v6 = Column(
- 'netmask_v6',
- String(length=255, convert_unicode=False, assert_unicode=None,
- unicode_error=None, _warn_on_bytestring=False))
-
-
-def upgrade(migrate_engine):
- # Upgrade operations go here. Don't create your own engine;
- # bind migrate_engine to your metadata
- meta.bind = migrate_engine
-
- # Alter column name
- networks.c.ra_server.alter(name='gateway_v6')
- # Add new column to existing table
- networks.create_column(networks_netmask_v6)
-
- # drop existing columns from table
- fixed_ips.c.addressV6.drop()
- fixed_ips.c.netmaskV6.drop()
- fixed_ips.c.gatewayV6.drop()
+# Copyright 2010 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.
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+
+# Table stub-definitions
+# Just for the ForeignKey and column creation to succeed, these are not the
+# actual definitions of instances or services.
+#
+
+#
+# Tables to alter
+#
+networks = Table('networks', meta,
+ Column('created_at', DateTime(timezone=False)),
+ Column('updated_at', DateTime(timezone=False)),
+ Column('deleted_at', DateTime(timezone=False)),
+ Column('deleted', Boolean(create_constraint=True, name=None)),
+ Column('id', Integer(), primary_key=True, nullable=False),
+ Column('injected', Boolean(create_constraint=True, name=None)),
+ Column('cidr',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('netmask',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('bridge',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('gateway',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('broadcast',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dns',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vlan', Integer()),
+ Column('vpn_public_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('vpn_public_port', Integer()),
+ Column('vpn_private_address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('dhcp_start',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('project_id',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('host',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('cidr_v6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('ra_server', String(length=255,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ Column(
+ 'label',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)))
+
+fixed_ips = Table('fixed_ips', meta,
+ Column('created_at', DateTime(timezone=False)),
+ Column('updated_at', DateTime(timezone=False)),
+ Column('deleted_at', DateTime(timezone=False)),
+ Column('deleted', Boolean(create_constraint=True, name=None)),
+ Column('id', Integer(), primary_key=True, nullable=False),
+ Column('address',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False)),
+ Column('network_id',
+ Integer(),
+ ForeignKey('networks.id'),
+ nullable=True),
+ Column('instance_id',
+ Integer(),
+ ForeignKey('instances.id'),
+ nullable=True),
+ Column('allocated', Boolean(create_constraint=True, name=None)),
+ Column('leased', Boolean(create_constraint=True, name=None)),
+ Column('reserved', Boolean(create_constraint=True, name=None)),
+ Column("addressV6", String(length=255,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ Column("netmaskV6", String(length=3,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ Column("gatewayV6", String(length=255,
+ convert_unicode=False,
+ assert_unicode=None,
+ unicode_error=None,
+ _warn_on_bytestring=False)),
+ )
+#
+# New Tables
+#
+# None
+
+#
+# Columns to add to existing tables
+#
+networks_netmask_v6 = Column(
+ 'netmask_v6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False))
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+
+ # Alter column name
+ networks.c.ra_server.alter(name='gateway_v6')
+ # Add new column to existing table
+ networks.create_column(networks_netmask_v6)
+
+ # drop existing columns from table
+ fixed_ips.c.addressV6.drop()
+ fixed_ips.c.netmaskV6.drop()
+ fixed_ips.c.gatewayV6.drop()
diff --git a/nova/tests/network/__init__.py b/nova/tests/network/__init__.py
index 8f71a30ba..e0d479f8c 100644
--- a/nova/tests/network/__init__.py
+++ b/nova/tests/network/__init__.py
@@ -1,47 +1,47 @@
-import os
-
-from nova import context
-from nova import db
-from nova import flags
-from nova import log as logging
-from nova import utils
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-def binpath(script):
- """Returns the absolute path to a script in bin"""
- return os.path.abspath(os.path.join(__file__, "../../../../bin", script))
-
-
-def lease_ip(private_ip):
- """Run add command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = (binpath('nova-dhcpbridge'), 'add',
- instance_ref['mac_address'],
- private_ip, 'fake')
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(*cmd, addl_env=env)
- LOG.debug("ISSUE_IP: %s, %s ", out, err)
-
-
-def release_ip(private_ip):
- """Run del command on dhcpbridge"""
- network_ref = db.fixed_ip_get_network(context.get_admin_context(),
- private_ip)
- instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
- private_ip)
- cmd = (binpath('nova-dhcpbridge'), 'del',
- instance_ref['mac_address'],
- private_ip, 'fake')
- env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
- 'TESTING': '1',
- 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
- (out, err) = utils.execute(*cmd, addl_env=env)
- LOG.debug("RELEASE_IP: %s, %s ", out, err)
+import os
+
+from nova import context
+from nova import db
+from nova import flags
+from nova import log as logging
+from nova import utils
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+def binpath(script):
+ """Returns the absolute path to a script in bin"""
+ return os.path.abspath(os.path.join(__file__, "../../../../bin", script))
+
+
+def lease_ip(private_ip):
+ """Run add command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = (binpath('nova-dhcpbridge'), 'add',
+ instance_ref['mac_address'],
+ private_ip, 'fake')
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(*cmd, addl_env=env)
+ LOG.debug("ISSUE_IP: %s, %s ", out, err)
+
+
+def release_ip(private_ip):
+ """Run del command on dhcpbridge"""
+ network_ref = db.fixed_ip_get_network(context.get_admin_context(),
+ private_ip)
+ instance_ref = db.fixed_ip_get_instance(context.get_admin_context(),
+ private_ip)
+ cmd = (binpath('nova-dhcpbridge'), 'del',
+ instance_ref['mac_address'],
+ private_ip, 'fake')
+ env = {'DNSMASQ_INTERFACE': network_ref['bridge'],
+ 'TESTING': '1',
+ 'FLAGFILE': FLAGS.dhcpbridge_flagfile}
+ (out, err) = utils.execute(*cmd, addl_env=env)
+ LOG.debug("RELEASE_IP: %s, %s ", out, err)
diff --git a/nova/tests/network/base.py b/nova/tests/network/base.py
index 2dd8178ff..988a1de72 100644
--- a/nova/tests/network/base.py
+++ b/nova/tests/network/base.py
@@ -1,154 +1,154 @@
-# 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.
-"""
-Base class of Unit Tests for all network models
-"""
-import IPy
-import os
-
-from nova import context
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import test
-from nova import utils
-from nova.auth import manager
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-class NetworkTestCase(test.TestCase):
- """Test cases for network code"""
- def setUp(self):
- super(NetworkTestCase, self).setUp()
- # NOTE(vish): if you change these flags, make sure to change the
- # flags in the corresponding section in nova-dhcpbridge
- self.flags(connection_type='fake',
- fake_call=True,
- fake_network=True)
- self.manager = manager.AuthManager()
- self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
- self.projects = []
- self.network = utils.import_object(FLAGS.network_manager)
- self.context = context.RequestContext(project=None, user=self.user)
- for i in range(FLAGS.num_networks):
- name = 'project%s' % i
- project = self.manager.create_project(name, 'netuser', name)
- self.projects.append(project)
- # create the necessary network data for the project
- user_context = context.RequestContext(project=self.projects[i],
- user=self.user)
- host = self.network.get_network_host(user_context.elevated())
- instance_ref = self._create_instance(0)
- self.instance_id = instance_ref['id']
- instance_ref = self._create_instance(1)
- self.instance2_id = instance_ref['id']
-
- def tearDown(self):
- # TODO(termie): this should really be instantiating clean datastores
- # in between runs, one failure kills all the tests
- db.instance_destroy(context.get_admin_context(), self.instance_id)
- db.instance_destroy(context.get_admin_context(), self.instance2_id)
- for project in self.projects:
- self.manager.delete_project(project)
- self.manager.delete_user(self.user)
- super(NetworkTestCase, self).tearDown()
-
- def _create_instance(self, project_num, mac=None):
- if not mac:
- mac = utils.generate_mac()
- project = self.projects[project_num]
- self.context._project = project
- self.context.project_id = project.id
- return db.instance_create(self.context,
- {'project_id': project.id,
- 'mac_address': mac})
-
- def _create_address(self, project_num, instance_id=None):
- """Create an address in given project num"""
- if instance_id is None:
- instance_id = self.instance_id
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- return self.network.allocate_fixed_ip(self.context, instance_id)
-
- def _deallocate_address(self, project_num, address):
- self.context._project = self.projects[project_num]
- self.context.project_id = self.projects[project_num].id
- self.network.deallocate_fixed_ip(self.context, address)
-
- def _is_allocated_in_project(self, address, project_id):
- """Returns true if address is in specified project"""
- project_net = db.network_get_by_bridge(context.get_admin_context(),
- FLAGS.flat_network_bridge)
- network = db.fixed_ip_get_network(context.get_admin_context(),
- address)
- instance = db.fixed_ip_get_instance(context.get_admin_context(),
- address)
- # instance exists until release
- return instance is not None and network['id'] == project_net['id']
-
- def test_private_ipv6(self):
- """Make sure ipv6 is OK"""
- if FLAGS.use_ipv6:
- instance_ref = self._create_instance(0)
- address = self._create_address(0, instance_ref['id'])
- network_ref = db.project_get_network(
- context.get_admin_context(),
- self.context.project_id)
- address_v6 = db.instance_get_fixed_address_v6(
- context.get_admin_context(),
- instance_ref['id'])
- self.assertEqual(instance_ref['mac_address'],
- utils.to_mac(address_v6))
- instance_ref2 = db.fixed_ip_get_instance_v6(
- context.get_admin_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']))
- self._deallocate_address(0, address)
- db.instance_destroy(context.get_admin_context(),
- instance_ref['id'])
-
- def test_available_ips(self):
- """Make sure the number of available ips for the network is correct
-
- The number of available IP addresses depends on the test
- environment's setup.
-
- Network size is set in test fixture's setUp method.
-
- There are ips reserved at the bottom and top of the range.
- services (network, gateway, CloudPipe, broadcast)
- """
- network = db.project_get_network(context.get_admin_context(),
- self.projects[0].id)
- net_size = flags.FLAGS.network_size
- admin_context = context.get_admin_context()
- total_ips = (db.network_count_available_ips(admin_context,
- network['id']) +
- db.network_count_reserved_ips(admin_context,
- network['id']) +
- db.network_count_allocated_ips(admin_context,
- network['id']))
- self.assertEqual(total_ips, net_size)
+# 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.
+"""
+Base class of Unit Tests for all network models
+"""
+import IPy
+import os
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class NetworkTestCase(test.TestCase):
+ """Test cases for network code"""
+ def setUp(self):
+ super(NetworkTestCase, self).setUp()
+ # NOTE(vish): if you change these flags, make sure to change the
+ # flags in the corresponding section in nova-dhcpbridge
+ self.flags(connection_type='fake',
+ fake_call=True,
+ fake_network=True)
+ self.manager = manager.AuthManager()
+ self.user = self.manager.create_user('netuser', 'netuser', 'netuser')
+ self.projects = []
+ self.network = utils.import_object(FLAGS.network_manager)
+ self.context = context.RequestContext(project=None, user=self.user)
+ for i in range(FLAGS.num_networks):
+ name = 'project%s' % i
+ project = self.manager.create_project(name, 'netuser', name)
+ self.projects.append(project)
+ # create the necessary network data for the project
+ user_context = context.RequestContext(project=self.projects[i],
+ user=self.user)
+ host = self.network.get_network_host(user_context.elevated())
+ instance_ref = self._create_instance(0)
+ self.instance_id = instance_ref['id']
+ instance_ref = self._create_instance(1)
+ self.instance2_id = instance_ref['id']
+
+ def tearDown(self):
+ # TODO(termie): this should really be instantiating clean datastores
+ # in between runs, one failure kills all the tests
+ db.instance_destroy(context.get_admin_context(), self.instance_id)
+ db.instance_destroy(context.get_admin_context(), self.instance2_id)
+ for project in self.projects:
+ self.manager.delete_project(project)
+ self.manager.delete_user(self.user)
+ super(NetworkTestCase, self).tearDown()
+
+ def _create_instance(self, project_num, mac=None):
+ if not mac:
+ mac = utils.generate_mac()
+ project = self.projects[project_num]
+ self.context._project = project
+ self.context.project_id = project.id
+ return db.instance_create(self.context,
+ {'project_id': project.id,
+ 'mac_address': mac})
+
+ def _create_address(self, project_num, instance_id=None):
+ """Create an address in given project num"""
+ if instance_id is None:
+ instance_id = self.instance_id
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ return self.network.allocate_fixed_ip(self.context, instance_id)
+
+ def _deallocate_address(self, project_num, address):
+ self.context._project = self.projects[project_num]
+ self.context.project_id = self.projects[project_num].id
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ def _is_allocated_in_project(self, address, project_id):
+ """Returns true if address is in specified project"""
+ project_net = db.network_get_by_bridge(context.get_admin_context(),
+ FLAGS.flat_network_bridge)
+ network = db.fixed_ip_get_network(context.get_admin_context(),
+ address)
+ instance = db.fixed_ip_get_instance(context.get_admin_context(),
+ address)
+ # instance exists until release
+ return instance is not None and network['id'] == project_net['id']
+
+ def test_private_ipv6(self):
+ """Make sure ipv6 is OK"""
+ if FLAGS.use_ipv6:
+ instance_ref = self._create_instance(0)
+ address = self._create_address(0, instance_ref['id'])
+ network_ref = db.project_get_network(
+ context.get_admin_context(),
+ self.context.project_id)
+ address_v6 = db.instance_get_fixed_address_v6(
+ context.get_admin_context(),
+ instance_ref['id'])
+ self.assertEqual(instance_ref['mac_address'],
+ utils.to_mac(address_v6))
+ instance_ref2 = db.fixed_ip_get_instance_v6(
+ context.get_admin_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']))
+ self._deallocate_address(0, address)
+ db.instance_destroy(context.get_admin_context(),
+ instance_ref['id'])
+
+ def test_available_ips(self):
+ """Make sure the number of available ips for the network is correct
+
+ The number of available IP addresses depends on the test
+ environment's setup.
+
+ Network size is set in test fixture's setUp method.
+
+ There are ips reserved at the bottom and top of the range.
+ services (network, gateway, CloudPipe, broadcast)
+ """
+ network = db.project_get_network(context.get_admin_context(),
+ self.projects[0].id)
+ net_size = flags.FLAGS.network_size
+ admin_context = context.get_admin_context()
+ total_ips = (db.network_count_available_ips(admin_context,
+ network['id']) +
+ db.network_count_reserved_ips(admin_context,
+ network['id']) +
+ db.network_count_allocated_ips(admin_context,
+ network['id']))
+ self.assertEqual(total_ips, net_size)
diff --git a/nova/tests/test_flat_network.py b/nova/tests/test_flat_network.py
index b6f7762c5..dcc617e25 100644
--- a/nova/tests/test_flat_network.py
+++ b/nova/tests/test_flat_network.py
@@ -1,161 +1,161 @@
-# 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.
-"""
-Unit Tests for flat network code
-"""
-import IPy
-import os
-import unittest
-
-from nova import context
-from nova import db
-from nova import exception
-from nova import flags
-from nova import log as logging
-from nova import test
-from nova import utils
-from nova.auth import manager
-from nova.tests.network import base
-
-
-FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.network')
-
-
-class FlatNetworkTestCase(base.NetworkTestCase):
- """Test cases for network code"""
- def test_public_network_association(self):
- """Makes sure that we can allocate a public ip"""
- # TODO(vish): better way of adding floating ips
-
- self.context._project = self.projects[0]
- self.context.project_id = self.projects[0].id
- pubnet = IPy.IP(flags.FLAGS.floating_range)
- address = str(pubnet[0])
- try:
- db.floating_ip_get_by_address(context.get_admin_context(), address)
- except exception.NotFound:
- db.floating_ip_create(context.get_admin_context(),
- {'address': address,
- 'host': FLAGS.host})
-
- self.assertRaises(NotImplementedError,
- self.network.allocate_floating_ip,
- self.context, self.projects[0].id)
-
- fix_addr = self._create_address(0)
- float_addr = address
- self.assertRaises(NotImplementedError,
- self.network.associate_floating_ip,
- self.context, float_addr, fix_addr)
-
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, None)
-
- self.assertRaises(NotImplementedError,
- self.network.disassociate_floating_ip,
- self.context, float_addr)
-
- address = db.instance_get_floating_address(context.get_admin_context(),
- self.instance_id)
- self.assertEqual(address, None)
-
- self.assertRaises(NotImplementedError,
- self.network.deallocate_floating_ip,
- self.context, float_addr)
-
- self.network.deallocate_fixed_ip(self.context, fix_addr)
- db.floating_ip_destroy(context.get_admin_context(), float_addr)
-
- def test_allocate_deallocate_fixed_ip(self):
- """Makes sure that we can allocate and deallocate a fixed ip"""
- address = self._create_address(0)
- self.assertTrue(self._is_allocated_in_project(address,
- self.projects[0].id))
- self._deallocate_address(0, address)
-
- # check if the fixed ip address is really deallocated
- self.assertFalse(self._is_allocated_in_project(address,
- self.projects[0].id))
-
- def test_side_effects(self):
- """Ensures allocating and releasing has no side effects"""
- address = self._create_address(0)
- address2 = self._create_address(1, self.instance2_id)
-
- self.assertTrue(self._is_allocated_in_project(address,
- self.projects[0].id))
- self.assertTrue(self._is_allocated_in_project(address2,
- self.projects[1].id))
-
- self._deallocate_address(0, address)
- self.assertFalse(self._is_allocated_in_project(address,
- self.projects[0].id))
-
- # First address release shouldn't affect the second
- self.assertTrue(self._is_allocated_in_project(address2,
- self.projects[0].id))
-
- self._deallocate_address(1, address2)
- self.assertFalse(self._is_allocated_in_project(address2,
- self.projects[1].id))
-
- def test_ips_are_reused(self):
- """Makes sure that ip addresses that are deallocated get reused"""
- address = self._create_address(0)
- self.network.deallocate_fixed_ip(self.context, address)
-
- address2 = self._create_address(0)
- self.assertEqual(address, address2)
-
- self.network.deallocate_fixed_ip(self.context, address2)
-
- def test_too_many_addresses(self):
- """Test for a NoMoreAddresses exception when all fixed ips are used.
- """
- admin_context = context.get_admin_context()
- network = db.project_get_network(admin_context, self.projects[0].id)
- num_available_ips = db.network_count_available_ips(admin_context,
- network['id'])
- addresses = []
- instance_ids = []
- for i in range(num_available_ips):
- instance_ref = self._create_instance(0)
- instance_ids.append(instance_ref['id'])
- address = self._create_address(0, instance_ref['id'])
- addresses.append(address)
-
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, 0)
- self.assertRaises(db.NoMoreAddresses,
- self.network.allocate_fixed_ip,
- self.context,
- 'foo')
-
- for i in range(num_available_ips):
- self.network.deallocate_fixed_ip(self.context, addresses[i])
- db.instance_destroy(context.get_admin_context(), instance_ids[i])
- ip_count = db.network_count_available_ips(context.get_admin_context(),
- network['id'])
- self.assertEqual(ip_count, num_available_ips)
-
- def run(self, result=None):
- if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
- super(FlatNetworkTestCase, self).run(result)
+# 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.
+"""
+Unit Tests for flat network code
+"""
+import IPy
+import os
+import unittest
+
+from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import utils
+from nova.auth import manager
+from nova.tests.network import base
+
+
+FLAGS = flags.FLAGS
+LOG = logging.getLogger('nova.tests.network')
+
+
+class FlatNetworkTestCase(base.NetworkTestCase):
+ """Test cases for network code"""
+ def test_public_network_association(self):
+ """Makes sure that we can allocate a public ip"""
+ # TODO(vish): better way of adding floating ips
+
+ self.context._project = self.projects[0]
+ self.context.project_id = self.projects[0].id
+ pubnet = IPy.IP(flags.FLAGS.floating_range)
+ address = str(pubnet[0])
+ try:
+ db.floating_ip_get_by_address(context.get_admin_context(), address)
+ except exception.NotFound:
+ db.floating_ip_create(context.get_admin_context(),
+ {'address': address,
+ 'host': FLAGS.host})
+
+ self.assertRaises(NotImplementedError,
+ self.network.allocate_floating_ip,
+ self.context, self.projects[0].id)
+
+ fix_addr = self._create_address(0)
+ float_addr = address
+ self.assertRaises(NotImplementedError,
+ self.network.associate_floating_ip,
+ self.context, float_addr, fix_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.disassociate_floating_ip,
+ self.context, float_addr)
+
+ address = db.instance_get_floating_address(context.get_admin_context(),
+ self.instance_id)
+ self.assertEqual(address, None)
+
+ self.assertRaises(NotImplementedError,
+ self.network.deallocate_floating_ip,
+ self.context, float_addr)
+
+ self.network.deallocate_fixed_ip(self.context, fix_addr)
+ db.floating_ip_destroy(context.get_admin_context(), float_addr)
+
+ def test_allocate_deallocate_fixed_ip(self):
+ """Makes sure that we can allocate and deallocate a fixed ip"""
+ address = self._create_address(0)
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self._deallocate_address(0, address)
+
+ # check if the fixed ip address is really deallocated
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
+
+ def test_side_effects(self):
+ """Ensures allocating and releasing has no side effects"""
+ address = self._create_address(0)
+ address2 = self._create_address(1, self.instance2_id)
+
+ self.assertTrue(self._is_allocated_in_project(address,
+ self.projects[0].id))
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ self._deallocate_address(0, address)
+ self.assertFalse(self._is_allocated_in_project(address,
+ self.projects[0].id))
+
+ # First address release shouldn't affect the second
+ self.assertTrue(self._is_allocated_in_project(address2,
+ self.projects[0].id))
+
+ self._deallocate_address(1, address2)
+ self.assertFalse(self._is_allocated_in_project(address2,
+ self.projects[1].id))
+
+ def test_ips_are_reused(self):
+ """Makes sure that ip addresses that are deallocated get reused"""
+ address = self._create_address(0)
+ self.network.deallocate_fixed_ip(self.context, address)
+
+ address2 = self._create_address(0)
+ self.assertEqual(address, address2)
+
+ self.network.deallocate_fixed_ip(self.context, address2)
+
+ def test_too_many_addresses(self):
+ """Test for a NoMoreAddresses exception when all fixed ips are used.
+ """
+ admin_context = context.get_admin_context()
+ network = db.project_get_network(admin_context, self.projects[0].id)
+ num_available_ips = db.network_count_available_ips(admin_context,
+ network['id'])
+ addresses = []
+ instance_ids = []
+ for i in range(num_available_ips):
+ instance_ref = self._create_instance(0)
+ instance_ids.append(instance_ref['id'])
+ address = self._create_address(0, instance_ref['id'])
+ addresses.append(address)
+
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, 0)
+ self.assertRaises(db.NoMoreAddresses,
+ self.network.allocate_fixed_ip,
+ self.context,
+ 'foo')
+
+ for i in range(num_available_ips):
+ self.network.deallocate_fixed_ip(self.context, addresses[i])
+ db.instance_destroy(context.get_admin_context(), instance_ids[i])
+ ip_count = db.network_count_available_ips(context.get_admin_context(),
+ network['id'])
+ self.assertEqual(ip_count, num_available_ips)
+
+ def run(self, result=None):
+ if(FLAGS.network_manager == 'nova.network.manager.FlatManager'):
+ super(FlatNetworkTestCase, self).run(result)
--
cgit
From 0e63a45f40a2069d497878b7c05d00522c3a2774 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 16:24:38 -0500
Subject: Again
---
nova/virt/xenapi/vmops.py | 13 ++++++++-----
nova/virt/xenapi_conn.py | 6 +++---
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 7525ff5ec..ab98ef000 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -85,8 +85,7 @@ class VMOps(object):
vm_ref = self._create_vm(instance, vdi_uuid)
self._spawn(instance, vm_ref)
- def _spawn(self, instance, vdi_uuid):
- """Spawn a new instance"""
+ def _create_vm(self, instance, vdi_uuid):
instance_name = instance.name
vm_ref = VMHelper.lookup(self._session, instance_name)
if vm_ref is not None:
@@ -131,8 +130,13 @@ class VMOps(object):
# inject_network_info and create vifs
networks = self.inject_network_info(instance)
self.create_vifs(instance, networks)
+ return vm_ref
+
+ def _spawn(self, instance, vm_ref):
+ """Spawn a new instance"""
LOG.debug(_('Starting VM %s...'), vm_ref)
self._start(instance, vm_ref)
+ instance_name = instance.name
LOG.info(_('Spawning VM %(instance_name)s created %(vm_ref)s.')
% locals())
@@ -365,10 +369,9 @@ class VMOps(object):
#TODO(mdietz): this will need to be adjusted for swap later
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
- LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %s megs") % (vdi_uuid,
- instance.name, new_disk_size))
+ LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %sGB") % (vdi_uuid,
+ instance.name, instance.local_gb))
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
-
self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
LOG.debug(_("Resize instance %s complete") % (instance.name))
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 99ec53c11..2b0f82a4a 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -168,9 +168,9 @@ class XenAPIConnection(object):
"""Completes a resize, turning on the migrated instance"""
vdi_uuid = self._vmops.link_disks(instance, disk_info['base_copy'],
disk_info['cow'])
- #vm_ref = self._vmops._create_vm(instance, vdi_uuid)
- #self._vmops.resize_instance(instance, vdi_uuid)
- self._vmops._spawn(instance, vdi_uuid)
+ vm_ref = self._vmops._create_vm(instance, vdi_uuid)
+ self._vmops.resize_instance(instance, vdi_uuid)
+ self._vmops._spawn(instance, vm_ref)
def snapshot(self, instance, image_id):
""" Create snapshot from a running VM instance """
--
cgit
From c7da5632e954c860defc322e971936a8d60eb8fd Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 16:55:58 -0500
Subject: foo
---
nova/virt/xenapi/vmops.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index ab98ef000..9719e05b9 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -308,7 +308,7 @@ class VMOps(object):
try:
# transfer the base copy
template_vm_ref, template_vdi_uuids = self._get_snapshot(instance)
- base_copy_uuid = template_vdi_uuids['snap']
+ base_copy_uuid = template_vdi_uuids['image']
vdi_ref, vm_vdi_rec = \
VMHelper.get_vdi_for_vm_safely(self._session, vm_ref)
cow_uuid = vm_vdi_rec['uuid']
--
cgit
From cc2d4728d32d016ef803d0def456cac6e315e8fa Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Wed, 16 Mar 2011 17:56:40 -0400
Subject: get started testing
---
nova/image/glance.py | 6 ++++--
nova/tests/image/__init__.py | 0
nova/tests/image/test_glance.py | 18 ++++++++++++++++++
3 files changed, 22 insertions(+), 2 deletions(-)
create mode 100644 nova/tests/image/__init__.py
create mode 100644 nova/tests/image/test_glance.py
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 15fca69b8..3b448db4b 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -37,8 +37,10 @@ GlanceClient = utils.import_class('glance.client.Client')
class GlanceImageService(service.BaseImageService):
"""Provides storage and retrieval of disk image objects within Glance."""
- def __init__(self):
- self.client = GlanceClient(FLAGS.glance_host, FLAGS.glance_port)
+ def __init__(self, client=None):
+ if client is None:
+ self.client = GlanceClient(FLAGS.glance_host, FLAGS.glance_port)
+ self.client = client
def index(self, context):
"""
diff --git a/nova/tests/image/__init__.py b/nova/tests/image/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
new file mode 100644
index 000000000..b568f593d
--- /dev/null
+++ b/nova/tests/image/test_glance.py
@@ -0,0 +1,18 @@
+import unittest
+
+from nova.image import glance
+
+class StubGlanceClient(object):
+
+ def __init__(self, images):
+ self._images = images
+
+ def get_image_meta(id):
+ return self._images[id]
+
+class TestGlance(unittest.TestCase):
+
+ def test(self):
+ images = {'xyz': "image"}
+ client = StubGlanceClient(images)
+ service = glance.GlanceImageService(client)
--
cgit
From 8385599f941c5fe886de570b67f5e57e64e96468 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 16:58:46 -0500
Subject: hurr
---
nova/db/sqlalchemy/api.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index f4773ce32..84db330ec 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2206,8 +2206,8 @@ def migration_get_by_instance_and_status(context, instance_id, status):
filter_by(instance_id=instance_id).\
filter_by(status=status).first()
if not result:
- raise exception.NotFound(_("No migration found with instance id %s")
- % migration_id)
+ raise exception.NotFound(_("No migration found for instance %d")
+ "with status %s" % (instance_id, status))
return result
--
cgit
From 524eb966045192dd535648929d70cac091d8e24e Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 17:00:22 -0500
Subject: hurr
---
nova/db/sqlalchemy/api.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 84db330ec..7e358e64b 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2206,8 +2206,8 @@ def migration_get_by_instance_and_status(context, instance_id, status):
filter_by(instance_id=instance_id).\
filter_by(status=status).first()
if not result:
- raise exception.NotFound(_("No migration found for instance %d")
- "with status %s" % (instance_id, status))
+ raise exception.NotFound(_("No migration found for instance %d"
+ "with status %s" % (instance_id, status)))
return result
--
cgit
From bf2f491f3e7aa5522d306c2182c3d220eb49a55f Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 17:56:48 -0500
Subject: foo
---
nova/compute/manager.py | 5 +++--
nova/db/sqlalchemy/api.py | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 351e02f51..e69544b6e 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -458,7 +458,7 @@ class ComputeManager(manager.Manager):
#Just roll back the record. There's no need to resize down since
#the 'old' VM already has the preferred attributes
- self.db.instance_update(context,
+ self.db.instance_update(context, instance_id
dict(memory_mb=instance_type['memory_mb'],
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
@@ -542,7 +542,8 @@ class ComputeManager(manager.Manager):
instance_type = self.db.instance_type_get_by_flavor_id(context,
migration_ref['new_flavor_id'])
self.db.instance_update(context, instance_id,
- dict(memory_mb=instance_type['memory_mb'],
+ dict(instance_type=instance_type['name'],
+ memory_mb=instance_type['memory_mb'],
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 7e358e64b..47b84af50 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2206,7 +2206,7 @@ def migration_get_by_instance_and_status(context, instance_id, status):
filter_by(instance_id=instance_id).\
filter_by(status=status).first()
if not result:
- raise exception.NotFound(_("No migration found for instance %d"
+ raise exception.NotFound(_("No migration found for instance %s"
"with status %s" % (instance_id, status)))
return result
--
cgit
From 3c0ae08b71c860383c215fa30c36693fd80f34c2 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Wed, 16 Mar 2011 17:58:16 -0500
Subject: foo
---
nova/compute/manager.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index e69544b6e..3135d5801 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -458,7 +458,7 @@ class ComputeManager(manager.Manager):
#Just roll back the record. There's no need to resize down since
#the 'old' VM already has the preferred attributes
- self.db.instance_update(context, instance_id
+ self.db.instance_update(context, instance_id,
dict(memory_mb=instance_type['memory_mb'],
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
--
cgit
From aa13754d04c17ae9985017e22ae4f68916bc2781 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 17 Mar 2011 10:03:47 -0500
Subject: Foo
---
nova/compute/manager.py | 1 -
nova/virt/xenapi/vmops.py | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 3135d5801..b8c3c24cd 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -547,7 +547,6 @@ class ComputeManager(manager.Manager):
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
- instance_ref = self.db.instance_get(context, instance_id)
self.driver.finish_resize(instance_ref, disk_info)
self.db.migration_update(context, migration_id,
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 9719e05b9..b5003f0f8 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -307,7 +307,7 @@ class VMOps(object):
template_vdi_uuids = template_vm_ref = None
try:
# transfer the base copy
- template_vm_ref, template_vdi_uuids = self._get_snapshot(instance)
+ template_vm_ref, template_vdi_uuids = selimage._get_snapshot(instance)
base_copy_uuid = template_vdi_uuids['image']
vdi_ref, vm_vdi_rec = \
VMHelper.get_vdi_for_vm_safely(self._session, vm_ref)
@@ -368,6 +368,7 @@ class VMOps(object):
"""Resize a running instance by changing it's RAM and disk size """
#TODO(mdietz): this will need to be adjusted for swap later
#The new disk size must be in bytes
+
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %sGB") % (vdi_uuid,
instance.name, instance.local_gb))
--
cgit
From 4f1f5bb1ed2cbb57e9ba8ea481ae31c0e6acc7bd Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 17 Mar 2011 11:03:07 -0500
Subject: refactoring
---
nova/compute/manager.py | 5 +----
nova/virt/xenapi/vmops.py | 22 +++++++++++++++++-----
nova/virt/xenapi_conn.py | 10 +++++-----
3 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index b8c3c24cd..6b784f1e3 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -463,7 +463,7 @@ class ComputeManager(manager.Manager):
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
- self.driver._start(instance_ref)
+ self.driver.revert_resize(instance_ref)
self.db.migration_update(context, migration_id,
{'status': 'reverted'})
@@ -514,8 +514,6 @@ class ComputeManager(manager.Manager):
self.db.migration_update(context, migration_id,
{'status': 'post-migrating', })
-
-
service = self.db.service_get_by_host_and_topic(context,
migration_ref['dest_compute'], FLAGS.compute_topic)
topic = self.db.queue_get_for(context, FLAGS.compute_topic,
@@ -536,7 +534,6 @@ class ComputeManager(manager.Manager):
migration_ref = self.db.migration_get(context, migration_id)
instance_ref = self.db.instance_get(context,
migration_ref['instance_id'])
-
#TODO(mdietz): apply the rest of the instance_type attributes going
#after they're supported
instance_type = self.db.instance_type_get_by_flavor_id(context,
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index b5003f0f8..ee99a9918 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -62,6 +62,17 @@ class VMOps(object):
vm_refs.append(vm_rec["name_label"])
return vm_refs
+ def revert_resize(self, instance):
+ vm_ref = VMHelper.lookup(self._session, instance.name)
+ self._start(instance, vm_ref)
+
+ def finish_resize(self, instance, disk_info):
+ vdi_uuid = self._vmops.link_disks(instance, disk_info['base_copy'],
+ disk_info['cow'])
+ vm_ref = self._create_vm(instance, vdi_uuid)
+ self.resize_instance(instance, vdi_uuid)
+ self._spawn(instance, vm_ref)
+
def _start(self, instance, vm_ref=None):
"""Power on a VM instance"""
if not vm_ref:
@@ -307,7 +318,8 @@ class VMOps(object):
template_vdi_uuids = template_vm_ref = None
try:
# transfer the base copy
- template_vm_ref, template_vdi_uuids = selimage._get_snapshot(instance)
+ template_vm_ref, template_vdi_uuids = \
+ self.image._get_snapshot(instance)
base_copy_uuid = template_vdi_uuids['image']
vdi_ref, vm_vdi_rec = \
VMHelper.get_vdi_for_vm_safely(self._session, vm_ref)
@@ -370,8 +382,8 @@ class VMOps(object):
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
- LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %sGB") % (vdi_uuid,
- instance.name, instance.local_gb))
+ LOG.debug(_("Resizpng VDI %s for instance %s. Expanding to %sGB") %
+ (vdi_uuid, instance.name, instance.local_gb))
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
LOG.debug(_("Resize instance %s complete") % (instance.name))
@@ -451,8 +463,8 @@ class VMOps(object):
state = self.get_info(instance['name'])['state']
if state == power_state.SHUTDOWN:
instance_name = instance.name
- LOG.warn(_("VM %(instance_name)s already halted, skipping shutdown...") %
- locals())
+ LOG.warn(_("VM %(instance_name)s already halted,"
+ "skipping shutdown...") % locals())
return
instance_id = instance.id
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 2b0f82a4a..da2fb51f1 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -164,13 +164,13 @@ class XenAPIConnection(object):
"""Create VM instance"""
self._vmops.spawn(instance)
+ def revert_resize(self, instance):
+ """Reverts a resize, powering back on the instance"""
+ self._vmops.revert_resize(instance)
+
def finish_resize(self, instance, disk_info):
"""Completes a resize, turning on the migrated instance"""
- vdi_uuid = self._vmops.link_disks(instance, disk_info['base_copy'],
- disk_info['cow'])
- vm_ref = self._vmops._create_vm(instance, vdi_uuid)
- self._vmops.resize_instance(instance, vdi_uuid)
- self._vmops._spawn(instance, vm_ref)
+ self._vmops.finish_resize(instance, disk_info)
def snapshot(self, instance, image_id):
""" Create snapshot from a running VM instance """
--
cgit
From 1ffef31839f3c1f4386d5df834af6d53483c09ed Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 17 Mar 2011 11:16:59 -0500
Subject: oh come on
---
nova/virt/xenapi/vmops.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index ee99a9918..b6bcc60ea 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -318,8 +318,7 @@ class VMOps(object):
template_vdi_uuids = template_vm_ref = None
try:
# transfer the base copy
- template_vm_ref, template_vdi_uuids = \
- self.image._get_snapshot(instance)
+ template_vm_ref, template_vdi_uuids = self._get_snapshot(instance)
base_copy_uuid = template_vdi_uuids['image']
vdi_ref, vm_vdi_rec = \
VMHelper.get_vdi_for_vm_safely(self._session, vm_ref)
--
cgit
From e79eaca86c4073cc8bc6c59be83d0f1bf5e2cea4 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Thu, 17 Mar 2011 12:20:22 -0400
Subject: glance image service show testcases
---
nova/image/glance.py | 14 +++++++++
nova/tests/image/test_glance.py | 64 ++++++++++++++++++++++++++++++++++++-----
2 files changed, 71 insertions(+), 7 deletions(-)
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 3b448db4b..d0c191ea1 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -18,6 +18,8 @@
from __future__ import absolute_import
+import datetime as dt
+
from glance.common import exception as glance_exception
from nova import exception
@@ -60,6 +62,18 @@ class GlanceImageService(service.BaseImageService):
"""
try:
image = self.client.get_image_meta(image_id)
+ if 'created_at' in image:
+ image['created_at'] = \
+ dt.datetime.strptime(image['created_at'],
+ "%Y-%m-%dT%H:%M:%S.%f")
+ if 'updated_at' in image:
+ image['updated_at'] = \
+ dt.datetime.strptime(image['updated_at'],
+ "%Y-%m-%dT%H:%M:%S.%f")
+ if 'deleted_at' in image and image['deleted_at'] is not None:
+ image['deleted_at'] = \
+ dt.datetime.strptime(image['deleted_at'],
+ "%Y-%m-%dT%H:%M:%S.%f")
except glance_exception.NotFound:
raise exception.NotFound
return image
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index b568f593d..971a32a17 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -1,3 +1,4 @@
+import datetime as dt
import unittest
from nova.image import glance
@@ -5,14 +6,63 @@ from nova.image import glance
class StubGlanceClient(object):
def __init__(self, images):
- self._images = images
+ self.images = images
- def get_image_meta(id):
- return self._images[id]
+ def get_image_meta(self, id):
+ return self.images[id]
+
+ def get_images_detailed(self):
+ return self.images
class TestGlance(unittest.TestCase):
- def test(self):
- images = {'xyz': "image"}
- client = StubGlanceClient(images)
- service = glance.GlanceImageService(client)
+ def setUp(self):
+ self.client = StubGlanceClient(None)
+ self.service = glance.GlanceImageService(self.client)
+
+ def test_show_passes_through_to_client(self):
+ self.client.images = {'xyz': "image"}
+ self.assertEqual(self.service.show({}, 'xyz'), "image")
+
+ def test_detail_passes_through_to_client(self):
+ self.client.images = "these are the images"
+ self.assertEqual(self.service.detail({}), self.client.images)
+
+ def test_show_makes_create_datetimes(self):
+ create_time = dt.datetime.utcnow()
+ self.client.images = {'xyz': {
+ 'id': "id",
+ 'name': "my awesome image",
+ 'created_at': create_time.isoformat(),
+ }}
+ actual = self.service.show({}, 'xyz')
+ self.assertEqual(actual['created_at'], create_time)
+
+ def test_show_makes_update_datetimes(self):
+ update_time = dt.datetime.utcnow()
+ self.client.images = {'abc': {
+ 'id': "id",
+ 'name': "my okay image",
+ 'updated_at': update_time.isoformat(),
+ }}
+ actual = self.service.show({}, 'abc')
+ self.assertEqual(actual['updated_at'], update_time)
+
+ def test_show_makes_delete_datetimes(self):
+ delete_time = dt.datetime.utcnow()
+ self.client.images = {'123': {
+ 'id': "123",
+ 'name': "my lame image",
+ 'deleted_at': delete_time.isoformat(),
+ }}
+ actual = self.service.show({}, '123')
+ self.assertEqual(actual['deleted_at'], delete_time)
+
+ def test_show_handles_deleted_at_none(self):
+ self.client.images = {'747': {
+ 'id': "747",
+ 'name': "not deleted",
+ 'deleted_at': None,
+ }}
+ actual = self.service.show({}, '747')
+ self.assertEqual(actual['deleted_at'], None)
--
cgit
From d6ae8e4c2f6011497b1db23fcbafb23b663f924d Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 17 Mar 2011 11:24:24 -0500
Subject: Foo
---
nova/compute/manager.py | 1 +
nova/virt/xenapi/vmops.py | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 6b784f1e3..186b6f6a5 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -544,6 +544,7 @@ class ComputeManager(manager.Manager):
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
+ instance_ref = self.db.instance_get(context, instance_id)
self.driver.finish_resize(instance_ref, disk_info)
self.db.migration_update(context, migration_id,
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index b6bcc60ea..326d43aa9 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -67,7 +67,7 @@ class VMOps(object):
self._start(instance, vm_ref)
def finish_resize(self, instance, disk_info):
- vdi_uuid = self._vmops.link_disks(instance, disk_info['base_copy'],
+ vdi_uuid = self.link_disks(instance, disk_info['base_copy'],
disk_info['cow'])
vm_ref = self._create_vm(instance, vdi_uuid)
self.resize_instance(instance, vdi_uuid)
--
cgit
From b135bc23cca1494049dd9978cb18b52f2b4d99c7 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Thu, 17 Mar 2011 12:30:32 -0400
Subject: refactor to simpler implementation
---
nova/image/glance.py | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/nova/image/glance.py b/nova/image/glance.py
index d0c191ea1..188b6e588 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -62,22 +62,25 @@ class GlanceImageService(service.BaseImageService):
"""
try:
image = self.client.get_image_meta(image_id)
- if 'created_at' in image:
- image['created_at'] = \
- dt.datetime.strptime(image['created_at'],
- "%Y-%m-%dT%H:%M:%S.%f")
- if 'updated_at' in image:
- image['updated_at'] = \
- dt.datetime.strptime(image['updated_at'],
- "%Y-%m-%dT%H:%M:%S.%f")
- if 'deleted_at' in image and image['deleted_at'] is not None:
- image['deleted_at'] = \
- dt.datetime.strptime(image['deleted_at'],
- "%Y-%m-%dT%H:%M:%S.%f")
except glance_exception.NotFound:
raise exception.NotFound
+ return self._convert_timestamps_to_datetimes(image)
+
+ def _convert_timestamps_to_datetimes(self, image):
+ """
+ Returns image with known timestamp fields converted to datetime objects
+ """
+ for attr in ['created_at', 'updated_at', 'deleted_at']:
+ if attr in image and image[attr] is not None:
+ image[attr] = self._parse_glance_iso8601_timestamp(image[attr])
return image
+ def _parse_glance_iso8601_timestamp(self, timestamp):
+ """
+ Parse a subset of iso8601 timestamps into datetime objects
+ """
+ return dt.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%f")
+
def show_by_name(self, context, name):
"""
Returns a dict containing image data for the given name.
--
cgit
From 686e113188aaf8195aed7bea8bf70c21b6bff498 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 17 Mar 2011 12:04:49 -0500
Subject: Mapping the resize status
---
nova/api/openstack/servers.py | 8 +++++++-
nova/compute/manager.py | 2 ++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 47ed254ec..59234b0de 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -61,7 +61,13 @@ def _translate_detail_keys(inst):
for k, v in mapped_keys.iteritems():
inst_dict[k] = inst[v]
- inst_dict['status'] = power_mapping[inst_dict['status']]
+ context = req.environ['nova.context'].elevated()
+ migration = self.db.migrate_get_by_instance_and_status(context,
+ inst['id'], 'finished')
+ if migration:
+ inst_dict['status'] = 'resize-confirm'
+ else
+ inst_dict['status'] = power_mapping[inst_dict['status']]
inst_dict['addresses'] = dict(public=[], private=[])
# grab single private fixed ip
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 186b6f6a5..7993298b9 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -544,6 +544,8 @@ class ComputeManager(manager.Manager):
vcpus=instance_type['vcpus'],
local_gb=instance_type['local_gb']))
+ # reload the updated instance ref
+ # FIXME: is there reload functionality?
instance_ref = self.db.instance_get(context, instance_id)
self.driver.finish_resize(instance_ref, disk_info)
--
cgit
From 3afeb8466fa9f005edc9da182b1e0af6ffb00ade Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 17 Mar 2011 12:05:43 -0500
Subject: Mapping the resize status
---
nova/api/openstack/servers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 59234b0de..fd835c247 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -66,7 +66,7 @@ def _translate_detail_keys(inst):
inst['id'], 'finished')
if migration:
inst_dict['status'] = 'resize-confirm'
- else
+ else:
inst_dict['status'] = power_mapping[inst_dict['status']]
inst_dict['addresses'] = dict(public=[], private=[])
--
cgit
From 3ee835c60d2b43086b1e324501025d1f0221da27 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Thu, 17 Mar 2011 13:50:41 -0400
Subject: handle timestamps in glance service detail
---
nova/image/glance.py | 3 ++-
nova/tests/image/test_glance.py | 27 ++++++++++++++++++++++++---
2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 188b6e588..7706a42e4 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -54,7 +54,8 @@ class GlanceImageService(service.BaseImageService):
"""
Calls out to Glance for a list of detailed image information
"""
- return self.client.get_images_detailed()
+ for image in self.client.get_images_detailed():
+ yield self._convert_timestamps_to_datetimes(image)
def show(self, context, image_id):
"""
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 971a32a17..16fe0e7c0 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -12,7 +12,7 @@ class StubGlanceClient(object):
return self.images[id]
def get_images_detailed(self):
- return self.images
+ return self.images.itervalues()
class TestGlance(unittest.TestCase):
@@ -25,8 +25,8 @@ class TestGlance(unittest.TestCase):
self.assertEqual(self.service.show({}, 'xyz'), "image")
def test_detail_passes_through_to_client(self):
- self.client.images = "these are the images"
- self.assertEqual(self.service.detail({}), self.client.images)
+ self.client.images = {1: "an image"}
+ self.assertEqual(list(self.service.detail({})), ["an image"])
def test_show_makes_create_datetimes(self):
create_time = dt.datetime.utcnow()
@@ -66,3 +66,24 @@ class TestGlance(unittest.TestCase):
}}
actual = self.service.show({}, '747')
self.assertEqual(actual['deleted_at'], None)
+
+ def test_detail_handles_timestamps(self):
+ now = dt.datetime.utcnow()
+ image1 = {
+ 'id': 1,
+ 'name': 'image 1',
+ 'created_at': now.isoformat(),
+ 'updated_at': now.isoformat(),
+ 'deleted_at': None,
+ }
+ image2 = {
+ 'id': 2,
+ 'name': 'image 2',
+ 'deleted_at': now.isoformat(),
+ }
+ self.client.images = {1: image1, 2: image2}
+ i1, i2 = self.service.detail({})
+ self.assertEqual(i1['created_at'], now)
+ self.assertEqual(i1['updated_at'], now)
+ self.assertEqual(i1['deleted_at'], None)
+ self.assertEqual(i2['deleted_at'], now)
--
cgit
From 66c237a4d321887830e5282781870525abf00365 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Thu, 17 Mar 2011 14:04:31 -0400
Subject: teach glance image server get to handle timestamps
---
nova/image/glance.py | 2 +-
nova/tests/image/test_glance.py | 30 +++++++++++++++++++++++++++++-
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 7706a42e4..f725fe176 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -108,7 +108,7 @@ class GlanceImageService(service.BaseImageService):
raise exception.NotFound
for chunk in image_chunks:
data.write(chunk)
- return metadata
+ return self._convert_timestamps_to_datetimes(metadata)
def create(self, context, metadata, data=None):
"""
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 16fe0e7c0..1e6c45219 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -14,7 +14,17 @@ class StubGlanceClient(object):
def get_images_detailed(self):
return self.images.itervalues()
-class TestGlance(unittest.TestCase):
+ def get_image(self, id):
+ return self.images[id], []
+
+
+class NullWriter(object):
+
+ def write(self, *arg, **kwargs):
+ pass
+
+
+class TestGlanceImageServiceDatetimes(unittest.TestCase):
def setUp(self):
self.client = StubGlanceClient(None)
@@ -87,3 +97,21 @@ class TestGlance(unittest.TestCase):
self.assertEqual(i1['updated_at'], now)
self.assertEqual(i1['deleted_at'], None)
self.assertEqual(i2['deleted_at'], now)
+
+ def test_get_handles_timestamps(self):
+ now = dt.datetime.utcnow()
+ self.client.images = {'abcd': {
+ 'id': 'abcd',
+ 'name': 'nifty image',
+ 'created_at': now.isoformat(),
+ 'updated_at': now.isoformat(),
+ 'deleted_at': now.isoformat(),
+ }}
+ actual = self.service.get({}, 'abcd', NullWriter())
+ for attr in ('created_at', 'updated_at', 'deleted_at'):
+ self.assertEqual(actual[attr], now)
+
+ def test_get_handles_deleted_at_none(self):
+ self.client.images = {'abcd': {'deleted_at': None}}
+ actual = self.service.get({}, 'abcd', NullWriter())
+ self.assertEqual(actual['deleted_at'], None)
--
cgit
From c8e474d04dce462650c2a9f57cbcb106ce3ef0c9 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Thu, 17 Mar 2011 14:05:08 -0400
Subject: pep8
---
nova/tests/image/test_glance.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 1e6c45219..9b17cf261 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -3,6 +3,7 @@ import unittest
from nova.image import glance
+
class StubGlanceClient(object):
def __init__(self, images):
--
cgit
From 4334ca9d6b0ac8a9b2edb1fbcbf0bc4df28b2961 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Thu, 17 Mar 2011 15:04:28 -0400
Subject: get api openstack test_images working
---
nova/image/glance.py | 7 ++++---
nova/tests/api/openstack/test_images.py | 8 ++++----
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/nova/image/glance.py b/nova/image/glance.py
index f725fe176..55dc5488d 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -42,7 +42,8 @@ class GlanceImageService(service.BaseImageService):
def __init__(self, client=None):
if client is None:
self.client = GlanceClient(FLAGS.glance_host, FLAGS.glance_port)
- self.client = client
+ else:
+ self.client = client
def index(self, context):
"""
@@ -54,8 +55,8 @@ class GlanceImageService(service.BaseImageService):
"""
Calls out to Glance for a list of detailed image information
"""
- for image in self.client.get_images_detailed():
- yield self._convert_timestamps_to_datetimes(image)
+ return [self._convert_timestamps_to_datetimes(image)
+ for image in self.client.get_images_detailed()]
def show(self, context, image_id):
"""
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index 76f758929..47dd11e5b 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -182,8 +182,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{'id': '23g2ogk23k4hhkk4k42l',
'imageId': '23g2ogk23k4hhkk4k42l',
'name': 'public image #1',
- 'created_at': str(datetime.datetime.utcnow()),
- 'updated_at': str(datetime.datetime.utcnow()),
+ 'created_at': datetime.datetime.utcnow().isoformat(),
+ 'updated_at': datetime.datetime.utcnow().isoformat(),
'deleted_at': None,
'deleted': False,
'is_public': True,
@@ -192,8 +192,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{'id': 'slkduhfas73kkaskgdas',
'imageId': 'slkduhfas73kkaskgdas',
'name': 'public image #2',
- 'created_at': str(datetime.datetime.utcnow()),
- 'updated_at': str(datetime.datetime.utcnow()),
+ 'created_at': datetime.datetime.utcnow().isoformat(),
+ 'updated_at': datetime.datetime.utcnow().isoformat(),
'deleted_at': None,
'deleted': False,
'is_public': True,
--
cgit
From 25c407b6ade499dd0bdd470e7fd46682c34a98b7 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Thu, 17 Mar 2011 19:13:09 +0000
Subject: Get the migration out
---
nova/api/openstack/servers.py | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index fd835c247..601a68508 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -20,6 +20,8 @@ import traceback
from webob import exc
from nova import compute
+from nova import context
+from nova import db
from nova import exception
from nova import flags
from nova import log as logging
@@ -61,12 +63,12 @@ def _translate_detail_keys(inst):
for k, v in mapped_keys.iteritems():
inst_dict[k] = inst[v]
- context = req.environ['nova.context'].elevated()
- migration = self.db.migrate_get_by_instance_and_status(context,
- inst['id'], 'finished')
- if migration:
+ ctxt = context.get_admin_context()
+ try:
+ migration = db.migration_get_by_instance_and_status(ctxt,
+ inst['id'], 'finished')
inst_dict['status'] = 'resize-confirm'
- else:
+ except Exception, e:
inst_dict['status'] = power_mapping[inst_dict['status']]
inst_dict['addresses'] = dict(public=[], private=[])
--
cgit
From 2f1a1d293915cde6e15c85e0bb43fb21ae26f7b0 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Thu, 17 Mar 2011 15:29:54 -0400
Subject: handle create and update requests, and update the base image service
documentation to reflect the (defacto) behavior
---
nova/image/glance.py | 7 +++---
nova/image/service.py | 4 +--
nova/tests/image/test_glance.py | 54 ++++++++++++++++++++++++++++++++++++++++-
3 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 55dc5488d..fbb578585 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -118,7 +118,8 @@ class GlanceImageService(service.BaseImageService):
:raises AlreadyExists if the image already exist.
"""
- return self.client.add_image(metadata, data)
+ return self._convert_timestamps_to_datetimes(
+ self.client.add_image(metadata, data))
def update(self, context, image_id, metadata, data=None):
"""Replace the contents of the given image with the new data.
@@ -127,10 +128,10 @@ class GlanceImageService(service.BaseImageService):
"""
try:
- result = self.client.update_image(image_id, metadata, data)
+ metadata = self.client.update_image(image_id, metadata, data)
except glance_exception.NotFound:
raise exception.NotFound
- return result
+ return self._convert_timestamps_to_datetimes(metadata)
def delete(self, context, image_id):
"""
diff --git a/nova/image/service.py b/nova/image/service.py
index 78d8f33e9..e907381c9 100644
--- a/nova/image/service.py
+++ b/nova/image/service.py
@@ -88,7 +88,7 @@ class BaseImageService(object):
def create(self, context, metadata, data=None):
"""
- Store the image metadata and data and return the new image id.
+ Store the image metadata and data and return the new image metadata.
:raises AlreadyExists if the image already exist.
@@ -96,7 +96,7 @@ class BaseImageService(object):
raise NotImplementedError
def update(self, context, image_id, metadata, data=None):
- """Update the given image with the new metadata and data.
+ """Update the given image metadata and data and return the metadata
:raises NotFound if the image does not exist.
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 9b17cf261..6e94aa909 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -6,8 +6,10 @@ from nova.image import glance
class StubGlanceClient(object):
- def __init__(self, images):
+ def __init__(self, images, add_response=None, update_response=None):
self.images = images
+ self.add_response = add_response
+ self.update_response = update_response
def get_image_meta(self, id):
return self.images[id]
@@ -18,6 +20,12 @@ class StubGlanceClient(object):
def get_image(self, id):
return self.images[id], []
+ def add_image(self, metadata, data):
+ return self.add_response
+
+ def update_image(self, image_id, metadata, data):
+ return self.update_response
+
class NullWriter(object):
@@ -116,3 +124,47 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.client.images = {'abcd': {'deleted_at': None}}
actual = self.service.get({}, 'abcd', NullWriter())
self.assertEqual(actual['deleted_at'], None)
+
+ def test_create_handles_timestamps(self):
+ now = dt.datetime.utcnow()
+ self.client.add_response = {
+ 'id': 'abcd',
+ 'name': 'blah',
+ 'created_at': now.isoformat(),
+ 'updated_at': now.isoformat(),
+ 'deleted_at': now.isoformat(),
+ }
+ actual = self.service.create({}, {})
+ for attr in ('created_at', 'updated_at', 'deleted_at'):
+ self.assertEqual(actual[attr], now)
+
+ def test_create_handles_deleted_at_none(self):
+ self.client.add_response = {
+ 'id': 'abcd',
+ 'name': 'blah',
+ 'deleted_at': None,
+ }
+ actual = self.service.create({}, {})
+ self.assertEqual(actual['deleted_at'], None)
+
+ def test_update_handles_timestamps(self):
+ now = dt.datetime.utcnow()
+ self.client.update_response = {
+ 'id': 'abcd',
+ 'name': 'blah',
+ 'created_at': now.isoformat(),
+ 'updated_at': now.isoformat(),
+ 'deleted_at': now.isoformat(),
+ }
+ actual = self.service.update({}, 'dummy_id', {})
+ for attr in ('created_at', 'updated_at', 'deleted_at'):
+ self.assertEqual(actual[attr], now)
+
+ def test_create_handles_deleted_at_none(self):
+ self.client.update_response = {
+ 'id': 'abcd',
+ 'name': 'blah',
+ 'deleted_at': None,
+ }
+ actual = self.service.update({}, 'dummy_id', {})
+ self.assertEqual(actual['deleted_at'], None)
--
cgit
From f7d5dea09568c6440918264d97ecdbcc316c0ec4 Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Thu, 17 Mar 2011 15:31:48 -0500
Subject: pep8
---
nova/api/openstack/servers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index b0e355232..050450457 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -69,7 +69,7 @@ def _translate_detail_keys(inst):
ctxt = context.get_admin_context()
try:
migration = db.migration_get_by_instance_and_status(ctxt,
- inst['id'], 'finished')
+ inst['id'], 'finished')
inst_dict['status'] = 'resize-confirm'
except Exception, e:
inst_dict['status'] = power_mapping[inst_dict['status']]
--
cgit
From b605b53e4b652e0a3f364d505b5fd7240fd4ea36 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Thu, 17 Mar 2011 20:44:15 +0000
Subject: Test changes
---
nova/tests/api/openstack/test_servers.py | 22 ++++++++++++----------
nova/tests/xenapi/stubs.py | 7 +++++--
2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 03e00af2a..14b72e097 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -491,16 +491,6 @@ class ServersTest(test.TestCase):
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
- def test_server_resize(self):
- body = dict(server=dict(
- name='server_test', imageId=2, flavorId=2, metadata={},
- personality={}))
- req = webob.Request.blank('/v1.0/servers/1/action')
- req.method = 'POST'
- req.content_type = 'application/json'
- req.body = json.dumps(body)
- res = req.get_response(fakes.wsgi_app())
-
def test_delete_server_instance(self):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'DELETE'
@@ -556,6 +546,18 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ def test_resized_server_has_correct_status(self):
+ req = self.webreq('/1', 'GET', dict(resize=dict(flavorId=3)))
+ def fake_migration_get(*args):
+ return {}
+
+ self.stubs.Set(nova.db, 'migration_get_by_instance_and_status',
+ fake_migration_get)
+ res = req.get_response(fakes.wsgi_app())
+ body = json.loads(res.body)
+ self.assertEqual(body['server']['status'], 'resize-confirm')
+
+
def test_confirm_resize_server(self):
req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py
index 70d46a1fb..7f9706a3d 100644
--- a/nova/tests/xenapi/stubs.py
+++ b/nova/tests/xenapi/stubs.py
@@ -228,6 +228,9 @@ class FakeSessionForMigrationTests(fake.SessionBase):
def VDI_get_by_uuid(*args):
return 'hurr'
+ def VDI_resize_online(*args):
+ pass
+
def VM_start(self, _1, ref, _2, _3):
vm = fake.get_record('VM', ref)
if vm['power_state'] != 'Halted':
@@ -240,7 +243,7 @@ class FakeSessionForMigrationTests(fake.SessionBase):
def stub_out_migration_methods(stubs):
def fake_get_snapshot(self, instance):
- return 'foo', 'bar'
+ return 'vm_ref', dict(image='foo', snap='bar')
@classmethod
def fake_get_vdi(cls, session, vm_ref):
@@ -249,7 +252,7 @@ def stub_out_migration_methods(stubs):
vdi_rec = session.get_xenapi().VDI.get_record(vdi_ref)
return vdi_ref, {'uuid': vdi_rec['uuid'], }
- def fake_shutdown(self, inst, vm, method='clean'):
+ def fake_shutdown(self, inst, vm, hard=True):
pass
@classmethod
--
cgit
From 8d5ffa079e768adec969a4e8ab540c24a7faaaa6 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Thu, 17 Mar 2011 20:45:18 +0000
Subject: Pep8
---
nova/tests/api/openstack/test_servers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 14b72e097..07ebfdd88 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -548,6 +548,7 @@ class ServersTest(test.TestCase):
def test_resized_server_has_correct_status(self):
req = self.webreq('/1', 'GET', dict(resize=dict(flavorId=3)))
+
def fake_migration_get(*args):
return {}
@@ -556,7 +557,6 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
body = json.loads(res.body)
self.assertEqual(body['server']['status'], 'resize-confirm')
-
def test_confirm_resize_server(self):
req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
--
cgit
From 2f4c1802c7e482a447d348f049ff429b3d1a640c Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Fri, 18 Mar 2011 16:06:43 -0400
Subject: fix date formatting in images controller show
---
nova/api/openstack/images.py | 6 +++++
nova/tests/api/openstack/fakes.py | 20 +++++++++-----
nova/tests/api/openstack/test_images.py | 46 ++++++++++++++++-----------------
3 files changed, 43 insertions(+), 29 deletions(-)
diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py
index 98f0dd96b..94e05823e 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -143,6 +143,7 @@ class Controller(wsgi.Controller):
image = self._service.show(req.environ['nova.context'], image_id)
_convert_image_id_to_hash(image)
+ self._format_image_dates(image)
return dict(image=image)
def delete(self, req, id):
@@ -164,3 +165,8 @@ class Controller(wsgi.Controller):
# Users may not modify public images, and that's all that
# we support for now.
raise faults.Fault(exc.HTTPNotFound())
+
+ def _format_image_dates(self, image):
+ for attr in ['created_at', 'updated_at', 'deleted_at']:
+ if image[attr] is not None:
+ image[attr] = image[attr].strftime('%Y-%m-%dT%H:%M:%SZ')
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 15f8a5b56..9573cf128 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import copy
import datetime
import json
import random
@@ -151,22 +152,23 @@ def stub_out_glance(stubs, initial_fixtures=None):
for f in self.fixtures]
def fake_get_images_detailed(self):
- return self.fixtures
+ return copy.deepcopy(self.fixtures)
def fake_get_image_meta(self, image_id):
- for f in self.fixtures:
- if f['id'] == image_id:
- return f
+ image = self._find_image(image_id)
+ if image:
+ return copy.deepcopy(image)
raise glance_exc.NotFound
def fake_add_image(self, image_meta, data=None):
+ image_meta = copy.deepcopy(image_meta)
id = ''.join(random.choice(string.letters) for _ in range(20))
image_meta['id'] = id
self.fixtures.append(image_meta)
return image_meta
def fake_update_image(self, image_id, image_meta, data=None):
- f = self.fake_get_image_meta(image_id)
+ f = self._find_image(image_id)
if not f:
raise glance_exc.NotFound
@@ -174,7 +176,7 @@ def stub_out_glance(stubs, initial_fixtures=None):
return f
def fake_delete_image(self, image_id):
- f = self.fake_get_image_meta(image_id)
+ f = self._find_image(image_id)
if not f:
raise glance_exc.NotFound
@@ -183,6 +185,12 @@ def stub_out_glance(stubs, initial_fixtures=None):
##def fake_delete_all(self):
## self.fixtures = []
+ def _find_image(self, image_id):
+ for f in self.fixtures:
+ if f['id'] == image_id:
+ return f
+ return None
+
GlanceClient = glance_client.Client
fake = FakeGlanceClient(initial_fixtures)
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index 47dd11e5b..b771966f1 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -21,7 +21,7 @@ and as a WSGI layer
"""
import json
-import datetime
+import datetime as dt
import shutil
import tempfile
@@ -177,13 +177,13 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
"""Test of the OpenStack API /images application controller"""
# Registered images at start of each test.
-
+ now = dt.datetime.utcnow()
IMAGE_FIXTURES = [
{'id': '23g2ogk23k4hhkk4k42l',
'imageId': '23g2ogk23k4hhkk4k42l',
'name': 'public image #1',
- 'created_at': datetime.datetime.utcnow().isoformat(),
- 'updated_at': datetime.datetime.utcnow().isoformat(),
+ 'created_at': now.isoformat(),
+ 'updated_at': now.isoformat(),
'deleted_at': None,
'deleted': False,
'is_public': True,
@@ -192,8 +192,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
{'id': 'slkduhfas73kkaskgdas',
'imageId': 'slkduhfas73kkaskgdas',
'name': 'public image #2',
- 'created_at': datetime.datetime.utcnow().isoformat(),
- 'updated_at': datetime.datetime.utcnow().isoformat(),
+ 'created_at': now.isoformat(),
+ 'updated_at': now.isoformat(),
'deleted_at': None,
'deleted': False,
'is_public': True,
@@ -235,20 +235,20 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
- def _is_equivalent_subset(x, y):
- if set(x) <= set(y):
- for k, v in x.iteritems():
- if x[k] != y[k]:
- if x[k] == 'active' and y[k] == 'available':
- continue
- return False
- return True
- return False
-
- for image in res_dict['images']:
- for image_fixture in self.IMAGE_FIXTURES:
- if _is_equivalent_subset(image, image_fixture):
- break
- else:
- self.assertEquals(1, 2, "image %s not in fixtures!" %
- str(image))
+ for image in self.IMAGE_FIXTURES:
+ expected = {
+ 'id': abs(hash(image['imageId'])),
+ 'name': image['name'],
+ 'status': 'active',
+ }
+ self.assertTrue(expected in res_dict['images'])
+
+ def test_show_image(self):
+ expected = self.IMAGE_FIXTURES[0]
+ id = abs(hash(expected['id']))
+ expected_time = self.now.strftime('%Y-%m-%dT%H:%M:%SZ')
+ req = webob.Request.blank('/v1.0/images/%s' % id)
+ res = req.get_response(fakes.wsgi_app())
+ actual = json.loads(res.body)['image']
+ self.assertEqual(expected_time, actual['created_at'])
+ self.assertEqual(expected_time, actual['updated_at'])
--
cgit
From 9351bd5538ea0fc0a77c4dee13406ac7a71ca1ae Mon Sep 17 00:00:00 2001
From: Cerberus
Date: Fri, 18 Mar 2011 17:01:44 -0500
Subject: Seriously?
---
nova/virt/xenapi/vmops.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index b27fe2216..4dca26f61 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -383,7 +383,7 @@ class VMOps(object):
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
- LOG.debug(_("Resizpng VDI %s for instance %s. Expanding to %sGB") %
+ LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %sGB") %
(vdi_uuid, instance.name, instance.local_gb))
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
--
cgit
From a3fe673108602e27cca132209e87369fa8bf1323 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Fri, 18 Mar 2011 19:46:04 -0700
Subject: Changed Copyright to NTT for newly added files for flatmanager ipv6
---
.../versions/012_add_ipv6_flatmanager.py | 2 +-
nova/tests/network/__init__.py | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index 5f5e3d007..8c9cf3377 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -1,4 +1,4 @@
-# Copyright 2010 OpenStack LLC.
+# Copyright (c) 2011 NTT.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/nova/tests/network/__init__.py b/nova/tests/network/__init__.py
index e0d479f8c..97f96b6fa 100644
--- a/nova/tests/network/__init__.py
+++ b/nova/tests/network/__init__.py
@@ -1,3 +1,23 @@
+# 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.
+"""
+Utility methods
+"""
import os
from nova import context
--
cgit
From 85f50cf496e2c193ddc715f3019b4a4769ab5bd9 Mon Sep 17 00:00:00 2001
From: Brian Waldon
Date: Mon, 21 Mar 2011 15:14:24 -0400
Subject: pep8; various fixes
---
nova/api/openstack/servers.py | 1 +
nova/api/openstack/views/servers.py | 5 ++---
nova/tests/api/openstack/test_servers.py | 17 +++++++++++++----
3 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index e3141934b..dafc096ba 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -513,6 +513,7 @@ class Controller(wsgi.Controller):
return kernel_id, ramdisk_id
+
class ControllerV10(Controller):
def _image_id_from_req_data(self, data):
return data['server']['imageId']
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 8d47ac757..078d5d484 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -67,9 +67,8 @@ class ViewBuilder(object):
# Return the metadata as a dictionary
metadata = {}
- if 'metadata' in inst:
- for item in inst['metadata']:
- metadata[item['key']] = item['value']
+ for item in inst.get('metadata', []):
+ metadata[item['key']] = item['value']
inst_dict['metadata'] = metadata
inst_dict['hostId'] = ''
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 6e78db9da..a9e76b244 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -311,10 +311,19 @@ class ServersTest(test.TestCase):
imageRef = 'http://localhost/v1.1/images/2'
flavorRef = 'http://localhost/v1.1/flavors/3'
- body = dict(server=dict(
- name='server_test', imageRef=imageRef, flavorRef=flavorRef,
- metadata={'hello': 'world', 'open': 'stack'},
- personality={}))
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': imageRef,
+ 'flavorRef': flavorRef,
+ 'metadata': {
+ 'hello': 'world',
+ 'open': 'stack',
+ },
+ 'personality': {},
+ },
+ }
+
req = webob.Request.blank('/v1.1/servers')
req.method = 'POST'
req.body = json.dumps(body)
--
cgit
From 8f7d6b9da89e7154a79ad7d20681d0cb47e042b7 Mon Sep 17 00:00:00 2001
From: Tushar Patil
Date: Mon, 21 Mar 2011 12:21:24 -0700
Subject: Fix for LP Bug #739641
---
smoketests/base.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/smoketests/base.py b/smoketests/base.py
index 3e2446c9a..31d82b20b 100644
--- a/smoketests/base.py
+++ b/smoketests/base.py
@@ -32,7 +32,6 @@ SUITE_NAMES = '[image, instance, volume]'
FLAGS = flags.FLAGS
flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
flags.DEFINE_integer('ssh_tries', 3, 'Numer of times to try ssh')
-boto_v6 = None
class SmokeTestCase(unittest.TestCase):
@@ -183,6 +182,9 @@ class SmokeTestCase(unittest.TestCase):
TEST_DATA = {}
+if FLAGS.use_ipv6:
+ global boto_v6
+ boto_v6 = __import__('boto_v6')
class UserSmokeTestCase(SmokeTestCase):
--
cgit
From 27ae9700739bd6a1e6f9db90e407f450ff3e770b Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Mon, 21 Mar 2011 16:35:38 -0400
Subject: added licenses
---
nova/tests/image/__init__.py | 17 +++++++++++++++++
nova/tests/image/test_glance.py | 19 +++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/nova/tests/image/__init__.py b/nova/tests/image/__init__.py
index e69de29bb..fae25bca7 100644
--- a/nova/tests/image/__init__.py
+++ b/nova/tests/image/__init__.py
@@ -0,0 +1,17 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 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.
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 6e94aa909..fcd686c84 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -1,3 +1,22 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 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 datetime as dt
import unittest
--
cgit
From 414c615a3ac2e61f312f8383f764114e7d782de1 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Mon, 21 Mar 2011 16:40:26 -0400
Subject: fix licenses
---
nova/tests/image/__init__.py | 3 +--
nova/tests/image/test_glance.py | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/nova/tests/image/__init__.py b/nova/tests/image/__init__.py
index fae25bca7..b94e2e54e 100644
--- a/nova/tests/image/__init__.py
+++ b/nova/tests/image/__init__.py
@@ -1,7 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2011 Openstack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index fcd686c84..d49b3dfdb 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -1,7 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2011 Openstack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
--
cgit
From 39783f386a473ed28c786bb72a29e8403503c40c Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Mon, 21 Mar 2011 17:09:53 -0400
Subject: make bcwaldon happy
---
nova/api/openstack/images.py | 2 +-
nova/image/glance.py | 6 +++---
nova/tests/api/openstack/test_images.py | 4 ++--
nova/tests/image/test_glance.py | 8 ++++----
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py
index 94e05823e..99c14275a 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -168,5 +168,5 @@ class Controller(wsgi.Controller):
def _format_image_dates(self, image):
for attr in ['created_at', 'updated_at', 'deleted_at']:
- if image[attr] is not None:
+ if image.get(attr) is not None:
image[attr] = image[attr].strftime('%Y-%m-%dT%H:%M:%SZ')
diff --git a/nova/image/glance.py b/nova/image/glance.py
index fbb578585..171b28fde 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -18,7 +18,7 @@
from __future__ import absolute_import
-import datetime as dt
+import datetime
from glance.common import exception as glance_exception
@@ -73,7 +73,7 @@ class GlanceImageService(service.BaseImageService):
Returns image with known timestamp fields converted to datetime objects
"""
for attr in ['created_at', 'updated_at', 'deleted_at']:
- if attr in image and image[attr] is not None:
+ if image.get(attr) is not None:
image[attr] = self._parse_glance_iso8601_timestamp(image[attr])
return image
@@ -81,7 +81,7 @@ class GlanceImageService(service.BaseImageService):
"""
Parse a subset of iso8601 timestamps into datetime objects
"""
- return dt.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%f")
+ return datetime.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%f")
def show_by_name(self, context, name):
"""
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index b771966f1..a866c764d 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -21,7 +21,7 @@ and as a WSGI layer
"""
import json
-import datetime as dt
+import datetime
import shutil
import tempfile
@@ -177,7 +177,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase):
"""Test of the OpenStack API /images application controller"""
# Registered images at start of each test.
- now = dt.datetime.utcnow()
+ now = datetime.datetime.utcnow()
IMAGE_FIXTURES = [
{'id': '23g2ogk23k4hhkk4k42l',
'imageId': '23g2ogk23k4hhkk4k42l',
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index d49b3dfdb..30021dbc1 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -58,12 +58,12 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.service = glance.GlanceImageService(self.client)
def test_show_passes_through_to_client(self):
- self.client.images = {'xyz': "image"}
- self.assertEqual(self.service.show({}, 'xyz'), "image")
+ self.client.images = {'xyz': {'foo': 'bar'}}
+ self.assertEqual(self.service.show({}, 'xyz'), {'foo': 'bar'})
def test_detail_passes_through_to_client(self):
- self.client.images = {1: "an image"}
- self.assertEqual(list(self.service.detail({})), ["an image"])
+ self.client.images = {1: {'foo': 'bar'}}
+ self.assertEqual(list(self.service.detail({})), [{'foo': 'bar'}])
def test_show_makes_create_datetimes(self):
create_time = dt.datetime.utcnow()
--
cgit
From 0cff0a13bac3539a46b3b932bfd016df7f190196 Mon Sep 17 00:00:00 2001
From: Vishvananda Ishaya
Date: Mon, 21 Mar 2011 14:20:13 -0700
Subject: import greenthread in libvirt
---
nova/virt/libvirt_conn.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index e80b9fbdf..f57f1a675 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -46,10 +46,9 @@ import time
import uuid
from xml.dom import minidom
-
+from eventlet import greenthread
from eventlet import tpool
from eventlet import semaphore
-
import IPy
from nova import context
--
cgit
From e1b9db2ac1af8f38084f9794a430e0292f110ed6 Mon Sep 17 00:00:00 2001
From: Mark Washenberger
Date: Mon, 21 Mar 2011 17:23:36 -0400
Subject: get rid of another datetime alias
---
nova/tests/image/test_glance.py | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 30021dbc1..f1f8504f3 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -16,7 +16,7 @@
# under the License.
-import datetime as dt
+import datetime
import unittest
from nova.image import glance
@@ -66,7 +66,7 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.assertEqual(list(self.service.detail({})), [{'foo': 'bar'}])
def test_show_makes_create_datetimes(self):
- create_time = dt.datetime.utcnow()
+ create_time = datetime.datetime.utcnow()
self.client.images = {'xyz': {
'id': "id",
'name': "my awesome image",
@@ -76,7 +76,7 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.assertEqual(actual['created_at'], create_time)
def test_show_makes_update_datetimes(self):
- update_time = dt.datetime.utcnow()
+ update_time = datetime.datetime.utcnow()
self.client.images = {'abc': {
'id': "id",
'name': "my okay image",
@@ -86,7 +86,7 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.assertEqual(actual['updated_at'], update_time)
def test_show_makes_delete_datetimes(self):
- delete_time = dt.datetime.utcnow()
+ delete_time = datetime.datetime.utcnow()
self.client.images = {'123': {
'id': "123",
'name': "my lame image",
@@ -105,7 +105,7 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.assertEqual(actual['deleted_at'], None)
def test_detail_handles_timestamps(self):
- now = dt.datetime.utcnow()
+ now = datetime.datetime.utcnow()
image1 = {
'id': 1,
'name': 'image 1',
@@ -126,7 +126,7 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.assertEqual(i2['deleted_at'], now)
def test_get_handles_timestamps(self):
- now = dt.datetime.utcnow()
+ now = datetime.datetime.utcnow()
self.client.images = {'abcd': {
'id': 'abcd',
'name': 'nifty image',
@@ -144,7 +144,7 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.assertEqual(actual['deleted_at'], None)
def test_create_handles_timestamps(self):
- now = dt.datetime.utcnow()
+ now = datetime.datetime.utcnow()
self.client.add_response = {
'id': 'abcd',
'name': 'blah',
@@ -166,7 +166,7 @@ class TestGlanceImageServiceDatetimes(unittest.TestCase):
self.assertEqual(actual['deleted_at'], None)
def test_update_handles_timestamps(self):
- now = dt.datetime.utcnow()
+ now = datetime.datetime.utcnow()
self.client.update_response = {
'id': 'abcd',
'name': 'blah',
--
cgit
From 4b8ed5afd1fd3e616eda0015f9bf16c7097f5476 Mon Sep 17 00:00:00 2001
From: Todd Willey
Date: Tue, 22 Mar 2011 03:13:12 -0400
Subject: vpn changes
---
nova/api/ec2/admin.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index d9a4ef999..208fe5c4f 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -28,6 +28,7 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova import utils
+from nova.api.ec2 import ec2utils
from nova.auth import manager
@@ -92,15 +93,18 @@ def vpn_dict(project, vpn_instance):
'public_ip': project.vpn_ip,
'public_port': project.vpn_port}
if vpn_instance:
- rv['instance_id'] = vpn_instance['ec2_id']
+ rv['instance_id'] = ec2utils.id_to_ec2_id(vpn_instance['id'])
rv['created_at'] = utils.isotime(vpn_instance['created_at'])
address = vpn_instance.get('fixed_ip', None)
if address:
rv['internal_ip'] = address['address']
- if utils.vpn_ping(project.vpn_ip, project.vpn_port):
- rv['state'] = 'running'
+ if project.vpn_ip and project.vpn_port:
+ if utils.vpn_ping(project.vpn_ip, project.vpn_port):
+ rv['state'] = 'running'
+ else:
+ rv['state'] = 'down'
else:
- rv['state'] = 'down'
+ rv['state'] = 'down - invalid project vpn config'
else:
rv['state'] = 'pending'
return rv
@@ -279,7 +283,7 @@ class AdminController(object):
", ensure it isn't running, and try "
"again in a few minutes")
instance = self._vpn_for(context, project)
- return {'instance_id': instance['ec2_id']}
+ return {'instance_id': ec2utils.id_to_ec2_id(instance['id'])}
def describe_vpns(self, context):
vpns = []
--
cgit
From d1860ce5d26fbbadb2310e8225e924879cde9a6c Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 10:35:43 +0100
Subject: Make synchronized support both external (file based) locks as well as
internal (semaphore based) locks. Attempt to make it native thread safe at
the expense of never cleaning up semaphores.
---
nova/tests/test_misc.py | 34 +++++++++++++++++++++++--
nova/utils.py | 67 +++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 92 insertions(+), 9 deletions(-)
diff --git a/nova/tests/test_misc.py b/nova/tests/test_misc.py
index 1fbaf304f..961499a60 100644
--- a/nova/tests/test_misc.py
+++ b/nova/tests/test_misc.py
@@ -16,8 +16,12 @@
import errno
import os
+import random
import select
+from eventlet import greenpool
+from eventlet import greenthread
+
from nova import test
from nova.utils import parse_mailmap, str_dict_replace, synchronized
@@ -72,11 +76,37 @@ class LockTestCase(test.TestCase):
self.assertEquals(foo.__name__, 'foo', "Wrapped function's name "
"got mangled")
- def test_synchronized(self):
+ def test_synchronized_internally(self):
+ """We can lock across multiple green threads"""
+ seen_threads = list()
+ @synchronized('testlock', external=False)
+ def f(id):
+ for x in range(10):
+ seen_threads.append(id)
+ greenthread.sleep(0)
+
+ threads = []
+ pool = greenpool.GreenPool(10)
+ for i in range(10):
+ threads.append(pool.spawn(f, i))
+
+ for thread in threads:
+ thread.wait()
+
+ self.assertEquals(len(seen_threads), 100)
+ # Looking at the seen threads, split it into chunks of 10, and verify
+ # that the last 9 match the first in each chunk.
+ for i in range(10):
+ for j in range(9):
+ self.assertEquals(seen_threads[i*10], seen_threads[i*10+1+j])
+
+
+ def test_synchronized_externally(self):
+ """We can lock across multiple processes"""
rpipe1, wpipe1 = os.pipe()
rpipe2, wpipe2 = os.pipe()
- @synchronized('testlock')
+ @synchronized('testlock', external=True)
def f(rpipe, wpipe):
try:
os.write(wpipe, "foo")
diff --git a/nova/utils.py b/nova/utils.py
index 499af2039..8936614cc 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -41,6 +41,7 @@ from xml.sax import saxutils
from eventlet import event
from eventlet import greenthread
+from eventlet import semaphore
from eventlet.green import subprocess
None
from nova import exception
@@ -531,17 +532,69 @@ def loads(s):
return json.loads(s)
-def synchronized(name):
+_semaphores_semaphore = semaphore.Semaphore()
+_semaphores = {}
+
+
+class _NoopContextManager(object):
+ def __enter__(self):
+ pass
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ pass
+
+
+def synchronized(name, external=False):
+ """Synchronization decorator
+
+ Decorating a method like so:
+ @synchronized('mylock')
+ def foo(self, *args):
+ ...
+
+ ensures that only one thread will execute the bar method at a time.
+
+ Different methods can share the same lock:
+ @synchronized('mylock')
+ def foo(self, *args):
+ ...
+
+ @synchronized('mylock')
+ def bar(self, *args):
+ ...
+
+ This way only one of either foo or bar can be executing at a time.
+
+ The external keyword argument denotes whether this lock should work across
+ multiple processes. This means that if two different workers both run a
+ a method decorated with @synchronized('mylock', external=True), only one
+ of them will execute at a time.
+ """
+
def wrap(f):
@functools.wraps(f)
def inner(*args, **kwargs):
- LOG.debug(_("Attempting to grab %(lock)s for method "
- "%(method)s..." % {"lock": name,
+ with _semaphores_semaphore:
+ if name not in _semaphores:
+ _semaphores[name] = semaphore.Semaphore()
+ sem = _semaphores[name]
+ LOG.debug(_('Attempting to grab semaphore "%(lock)s" for method '
+ '"%(method)s"...' % {"lock": name,
"method": f.__name__}))
- lock = lockfile.FileLock(os.path.join(FLAGS.lock_path,
- 'nova-%s.lock' % name))
- with lock:
- return f(*args, **kwargs)
+ with sem:
+ if external:
+ LOG.debug(_('Attempting to grab file lock "%(lock)s" for '
+ 'method "%(method)s"...' %
+ {"lock": name, "method": f.__name__}))
+ lock_file_path = os.path.join(FLAGS.lock_path,
+ 'nova-%s.lock' % name)
+ lock = lockfile.FileLock(lock_file_path)
+ else:
+ lock = _NoopContextManager()
+
+ with lock:
+ return f(*args, **kwargs)
+
return inner
return wrap
--
cgit
From e827b8dbae1faef2cc070c7e26395979571bcd46 Mon Sep 17 00:00:00 2001
From: Hisaharu Ishii
Date: Tue, 22 Mar 2011 20:27:51 +0900
Subject: Wrap update_ra in utils.synchronized.
---
nova/network/linux_net.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index ee36407a6..e283dee37 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -595,6 +595,7 @@ def update_dhcp(context, network_id):
_execute(*command, addl_env=env)
+@utils.synchronized('radvd_start')
def update_ra(context, network_id):
network_ref = db.network_get(context, network_id)
--
cgit
From 60a3aa86db1d0e1ea2f680c9587881e45fa99336 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 14:14:47 +0100
Subject: Make synchronized decorator not leak semaphores, at the expense of
not being truly thread safe (but safe enough for Eventlet style green
threads).
---
nova/network/linux_net.py | 2 +-
nova/tests/test_misc.py | 1 -
nova/utils.py | 18 +++++++++++++-----
3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index ee36407a6..9bb1685c0 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -274,7 +274,7 @@ class IptablesManager(object):
self.semaphore = semaphore.Semaphore()
- @utils.synchronized('iptables')
+ @utils.synchronized('iptables', external=True)
def apply(self):
"""Apply the current in-memory set of iptables rules
diff --git a/nova/tests/test_misc.py b/nova/tests/test_misc.py
index 961499a60..c0c72bb12 100644
--- a/nova/tests/test_misc.py
+++ b/nova/tests/test_misc.py
@@ -16,7 +16,6 @@
import errno
import os
-import random
import select
from eventlet import greenpool
diff --git a/nova/utils.py b/nova/utils.py
index 8936614cc..c580e805a 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -574,10 +574,12 @@ def synchronized(name, external=False):
def wrap(f):
@functools.wraps(f)
def inner(*args, **kwargs):
- with _semaphores_semaphore:
- if name not in _semaphores:
- _semaphores[name] = semaphore.Semaphore()
- sem = _semaphores[name]
+ # NOTE(soren): If we ever go natively threaded, this will be racy.
+ # See http://stackoverflow.com/questions/5390569/dyn\
+ # amically-allocating-and-destroying-mutexes
+ if name not in _semaphores:
+ _semaphores[name] = semaphore.Semaphore()
+ sem = _semaphores[name]
LOG.debug(_('Attempting to grab semaphore "%(lock)s" for method '
'"%(method)s"...' % {"lock": name,
"method": f.__name__}))
@@ -593,8 +595,14 @@ def synchronized(name, external=False):
lock = _NoopContextManager()
with lock:
- return f(*args, **kwargs)
+ retval = f(*args, **kwargs)
+ # If no-one else is waiting for it, delete it.
+ # See note about possible raciness above.
+ if not sem.balance < 1:
+ del _semaphores[name]
+
+ return retval
return inner
return wrap
--
cgit
From 62f9cc7cee30332143bf4e6e54fd21335db3c8da Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 14:36:32 +0100
Subject: Convert _cache_image to use utils.synchronized decorator. Disable its
test case, since I think it is no longer needed with the tests for
synchronized.
---
nova/tests/test_virt.py | 2 +-
nova/virt/libvirt_conn.py | 10 ++++------
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py
index b214f5ce7..b9cd30a79 100644
--- a/nova/tests/test_virt.py
+++ b/nova/tests/test_virt.py
@@ -62,7 +62,7 @@ class CacheConcurrencyTestCase(test.TestCase):
self.stubs.Set(os.path, 'exists', fake_exists)
self.stubs.Set(utils, 'execute', fake_execute)
- def test_same_fname_concurrency(self):
+ def notest_same_fname_concurrency(self):
"""Ensures that the same fname cache runs at a sequentially"""
conn = libvirt_conn.LibvirtConnection
wait1 = eventlet.event.Event()
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index e80b9fbdf..ca8d81f5f 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -48,7 +48,6 @@ from xml.dom import minidom
from eventlet import tpool
-from eventlet import semaphore
import IPy
@@ -552,13 +551,12 @@ class LibvirtConnection(object):
os.mkdir(base_dir)
base = os.path.join(base_dir, fname)
- if fname not in LibvirtConnection._image_sems:
- LibvirtConnection._image_sems[fname] = semaphore.Semaphore()
- with LibvirtConnection._image_sems[fname]:
+ @utils.synchronized(fname)
+ def call_if_not_exists(base, fn, *args, **kwargs):
if not os.path.exists(base):
fn(target=base, *args, **kwargs)
- if not LibvirtConnection._image_sems[fname].locked():
- del LibvirtConnection._image_sems[fname]
+
+ call_if_not_exists(base, fn, *args, **kwargs)
if cow:
utils.execute('qemu-img', 'create', '-f', 'qcow2', '-o',
--
cgit
--
cgit
From 01e7e598d0eb4aab9c3e7f69926a2875cdf22136 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 14:39:35 +0100
Subject: Get rid of IptablesManager's explicit semaphore.
---
nova/network/linux_net.py | 4 ----
nova/virt/libvirt_conn.py | 11 ++++-------
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 9bb1685c0..8cbf8db24 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -21,8 +21,6 @@ import inspect
import os
import calendar
-from eventlet import semaphore
-
from nova import db
from nova import exception
from nova import flags
@@ -272,8 +270,6 @@ class IptablesManager(object):
self.ipv4['nat'].add_chain('floating-snat')
self.ipv4['nat'].add_rule('snat', '-j $floating-snat')
- self.semaphore = semaphore.Semaphore()
-
@utils.synchronized('iptables', external=True)
def apply(self):
"""Apply the current in-memory set of iptables rules
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index ca8d81f5f..902866167 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -1766,14 +1766,11 @@ class IptablesFirewallDriver(FirewallDriver):
def refresh_security_group_members(self, security_group):
pass
+ @utils.synchronized('iptables', external=True)
def refresh_security_group_rules(self, security_group):
- # We use the semaphore to make sure noone applies the rule set
- # after we've yanked the existing rules but before we've put in
- # the new ones.
- with self.iptables.semaphore:
- for instance in self.instances.values():
- self.remove_filters_for_instance(instance)
- self.add_filters_for_instance(instance)
+ for instance in self.instances.values():
+ self.remove_filters_for_instance(instance)
+ self.add_filters_for_instance(instance)
self.iptables.apply()
def _security_group_chain_name(self, security_group_id):
--
cgit
From 804083b6ba811834c0bf9d5e2edcdf0130d7d1ce Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 14:50:53 +0100
Subject: IptablesManager.semaphore is no more.
---
nova/network/linux_net.py | 37 ++++++++++++++++---------------------
1 file changed, 16 insertions(+), 21 deletions(-)
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 8cbf8db24..9faa7de07 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -277,28 +277,23 @@ class IptablesManager(object):
This will blow away any rules left over from previous runs of the
same component of Nova, and replace them with our current set of
rules. This happens atomically, thanks to iptables-restore.
-
- We wrap the call in a semaphore lock, so that we don't race with
- ourselves. In the event of a race with another component running
- an iptables-* command at the same time, we retry up to 5 times.
"""
- with self.semaphore:
- s = [('iptables', self.ipv4)]
- if FLAGS.use_ipv6:
- s += [('ip6tables', self.ipv6)]
-
- for cmd, tables in s:
- for table in tables:
- current_table, _ = self.execute('sudo',
- '%s-save' % (cmd,),
- '-t', '%s' % (table,),
- attempts=5)
- current_lines = current_table.split('\n')
- new_filter = self._modify_rules(current_lines,
- tables[table])
- self.execute('sudo', '%s-restore' % (cmd,),
- process_input='\n'.join(new_filter),
- attempts=5)
+ s = [('iptables', self.ipv4)]
+ if FLAGS.use_ipv6:
+ s += [('ip6tables', self.ipv6)]
+
+ for cmd, tables in s:
+ for table in tables:
+ current_table, _ = self.execute('sudo',
+ '%s-save' % (cmd,),
+ '-t', '%s' % (table,),
+ attempts=5)
+ current_lines = current_table.split('\n')
+ new_filter = self._modify_rules(current_lines,
+ tables[table])
+ self.execute('sudo', '%s-restore' % (cmd,),
+ process_input='\n'.join(new_filter),
+ attempts=5)
def _modify_rules(self, current_lines, table, binary=None):
unwrapped_chains = table.unwrapped_chains
--
cgit
From de2ecf115ff0baf43fa530807997513c728ffdaf Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 15:16:08 +0100
Subject: Fix locking problem in security group refresh code.
---
nova/virt/libvirt_conn.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 902866167..fcd78b3b2 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -1766,12 +1766,15 @@ class IptablesFirewallDriver(FirewallDriver):
def refresh_security_group_members(self, security_group):
pass
- @utils.synchronized('iptables', external=True)
def refresh_security_group_rules(self, security_group):
+ self.do_refresh_security_group_rules(security_group)
+ self.iptables.apply()
+
+ @utils.synchronized('iptables', external=True)
+ def do_refresh_security_group_rules(self, security_group):
for instance in self.instances.values():
self.remove_filters_for_instance(instance)
self.add_filters_for_instance(instance)
- self.iptables.apply()
def _security_group_chain_name(self, security_group_id):
return 'nova-sg-%s' % (security_group_id,)
--
cgit
--
cgit
From d2494199df440809bbfbc55868b0dd57053868ed Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 16:23:47 +0100
Subject: Remove checks in _cache_image tests that were too implementation
specific.
---
nova/tests/test_virt.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py
index b9cd30a79..6bafac39f 100644
--- a/nova/tests/test_virt.py
+++ b/nova/tests/test_virt.py
@@ -62,7 +62,7 @@ class CacheConcurrencyTestCase(test.TestCase):
self.stubs.Set(os.path, 'exists', fake_exists)
self.stubs.Set(utils, 'execute', fake_execute)
- def notest_same_fname_concurrency(self):
+ def test_same_fname_concurrency(self):
"""Ensures that the same fname cache runs at a sequentially"""
conn = libvirt_conn.LibvirtConnection
wait1 = eventlet.event.Event()
@@ -77,13 +77,11 @@ class CacheConcurrencyTestCase(test.TestCase):
eventlet.sleep(0)
try:
self.assertFalse(done2.ready())
- self.assertTrue('fname' in conn._image_sems)
finally:
wait1.send()
done1.wait()
eventlet.sleep(0)
self.assertTrue(done2.ready())
- self.assertFalse('fname' in conn._image_sems)
def test_different_fname_concurrency(self):
"""Ensures that two different fname caches are concurrent"""
--
cgit
From 9aac55b650e9f39c5771d4683e51af5eac6204bb Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 16:24:03 +0100
Subject: Add a test for leaked semaphores.
---
nova/tests/test_misc.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/nova/tests/test_misc.py b/nova/tests/test_misc.py
index c0c72bb12..8fc5d67c0 100644
--- a/nova/tests/test_misc.py
+++ b/nova/tests/test_misc.py
@@ -22,7 +22,8 @@ from eventlet import greenpool
from eventlet import greenthread
from nova import test
-from nova.utils import parse_mailmap, str_dict_replace, synchronized
+from nova import utils
+from nova.utils import parse_mailmap, str_dict_replace
class ProjectTestCase(test.TestCase):
@@ -66,7 +67,7 @@ class ProjectTestCase(test.TestCase):
class LockTestCase(test.TestCase):
def test_synchronized_wrapped_function_metadata(self):
- @synchronized('whatever')
+ @utils.synchronized('whatever')
def foo():
"""Bar"""
pass
@@ -77,8 +78,9 @@ class LockTestCase(test.TestCase):
def test_synchronized_internally(self):
"""We can lock across multiple green threads"""
+ saved_sem_num = len(utils._semaphores)
seen_threads = list()
- @synchronized('testlock', external=False)
+ @utils.synchronized('testlock2', external=False)
def f(id):
for x in range(10):
seen_threads.append(id)
@@ -99,13 +101,15 @@ class LockTestCase(test.TestCase):
for j in range(9):
self.assertEquals(seen_threads[i*10], seen_threads[i*10+1+j])
+ self.assertEqual(saved_sem_num, len(utils._semaphores),
+ "Semaphore leak detected")
def test_synchronized_externally(self):
"""We can lock across multiple processes"""
rpipe1, wpipe1 = os.pipe()
rpipe2, wpipe2 = os.pipe()
- @synchronized('testlock', external=True)
+ @utils.synchronized('testlock1', external=True)
def f(rpipe, wpipe):
try:
os.write(wpipe, "foo")
--
cgit
From b2bdeb82024b1a015ccb2ad14606d6e9ccf80aa8 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 16:29:37 +0100
Subject: pep8
---
nova/tests/test_misc.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/nova/tests/test_misc.py b/nova/tests/test_misc.py
index 8fc5d67c0..4e17e1ce0 100644
--- a/nova/tests/test_misc.py
+++ b/nova/tests/test_misc.py
@@ -80,6 +80,7 @@ class LockTestCase(test.TestCase):
"""We can lock across multiple green threads"""
saved_sem_num = len(utils._semaphores)
seen_threads = list()
+
@utils.synchronized('testlock2', external=False)
def f(id):
for x in range(10):
@@ -99,7 +100,8 @@ class LockTestCase(test.TestCase):
# that the last 9 match the first in each chunk.
for i in range(10):
for j in range(9):
- self.assertEquals(seen_threads[i*10], seen_threads[i*10+1+j])
+ self.assertEquals(seen_threads[i * 10],
+ seen_threads[i * 10 + 1 + j])
self.assertEqual(saved_sem_num, len(utils._semaphores),
"Semaphore leak detected")
--
cgit
From 3c7de6db490a8482f6d1fb5fefc750050cb1e269 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 16:42:37 +0100
Subject: Pass a fake timing source to
test_ensure_filtering_rules_for_instance_timeout, shaving off 30 seconds of
test run time.
---
nova/tests/test_virt.py | 15 ++++++++++++++-
nova/virt/libvirt_conn.py | 10 +++++++---
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py
index b214f5ce7..a754f451a 100644
--- a/nova/tests/test_virt.py
+++ b/nova/tests/test_virt.py
@@ -429,6 +429,15 @@ class LibvirtConnTestCase(test.TestCase):
def fake_raise(self):
raise libvirt.libvirtError('ERR')
+ class FakeTime(object):
+ def __init__(self):
+ self.counter = 0
+
+ def sleep(self, t):
+ self.counter += t
+
+ fake_timer = FakeTime()
+
self.create_fake_libvirt_mock(nwfilterLookupByName=fake_raise)
instance_ref = db.instance_create(self.context, self.test_instance)
@@ -438,11 +447,15 @@ class LibvirtConnTestCase(test.TestCase):
conn = libvirt_conn.LibvirtConnection(False)
conn.firewall_driver.setattr('setup_basic_filtering', fake_none)
conn.firewall_driver.setattr('prepare_instance_filter', fake_none)
- conn.ensure_filtering_rules_for_instance(instance_ref)
+ conn.ensure_filtering_rules_for_instance(instance_ref,
+ time=fake_timer)
except exception.Error, e:
c1 = (0 <= e.message.find('Timeout migrating for'))
self.assertTrue(c1)
+ self.assertEqual(29, fake_timer.counter, "Didn't wait the expected "
+ "amount of time")
+
db.instance_destroy(self.context, instance_ref['id'])
def test_live_migration_raises_exception(self):
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index e80b9fbdf..de4a8fbca 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -42,13 +42,13 @@ import shutil
import sys
import random
import subprocess
-import time
import uuid
from xml.dom import minidom
-from eventlet import tpool
+from eventlet import greenthread
from eventlet import semaphore
+from eventlet import tpool
import IPy
@@ -1133,7 +1133,8 @@ class LibvirtConnection(object):
return
- def ensure_filtering_rules_for_instance(self, instance_ref):
+ def ensure_filtering_rules_for_instance(self, instance_ref,
+ time=None):
"""Setting up filtering rules and waiting for its completion.
To migrate an instance, filtering rules to hypervisors
@@ -1157,6 +1158,9 @@ class LibvirtConnection(object):
"""
+ if not time:
+ time = greenthread
+
# If any instances never launch at destination host,
# basic-filtering must be set here.
self.firewall_driver.setup_basic_filtering(instance_ref)
--
cgit
From 4e33ab9fc16d580fbcf57da8e6e2228ad27cc1af Mon Sep 17 00:00:00 2001
From: Naveed Massjouni
Date: Tue, 22 Mar 2011 11:46:00 -0400
Subject: Adding more docstrings. image_id and instance_type fields of an
instance will always exist, so no reason to check if keys exist.
---
nova/api/openstack/__init__.py | 4 ++++
nova/api/openstack/views/servers.py | 25 ++++++++++++-------------
2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 35b04f863..21d354f1c 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -131,6 +131,8 @@ class APIRouter(wsgi.Router):
class APIRouterV10(APIRouter):
+ ''' Defines routes specific to OpenStack API V1.0 '''
+
def _setup_routes(self, mapper):
APIRouter._setup_routes(self, mapper)
mapper.resource("server", "servers",
@@ -140,6 +142,8 @@ class APIRouterV10(APIRouter):
class APIRouterV11(APIRouter):
+ ''' Defines routes specific to OpenStack API V1.1 '''
+
def _setup_routes(self, mapper):
APIRouter._setup_routes(self, mapper)
mapper.resource("server", "servers",
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 078d5d484..3100c46b5 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -34,19 +34,18 @@ class ViewBuilder(object):
self.addresses_builder = addresses_builder
def build(self, inst, is_detail):
- """
- Coerces into dictionary format, mapping everything to
- Rackspace-like attributes for return
- """
+ ''' Returns a dict that represenst a server '''
if is_detail:
return self._build_detail(inst)
else:
return self._build_simple(inst)
def _build_simple(self, inst):
- return dict(server=dict(id=inst['id'], name=inst['display_name']))
+ ''' Returns a simple model of a server '''
+ return dict(server=dict(id=inst['id'], name=inst['display_name']))
def _build_detail(self, inst):
+ ''' Returns a detailed model of a server '''
power_mapping = {
None: 'build',
power_state.NOSTATE: 'build',
@@ -81,36 +80,36 @@ class ViewBuilder(object):
return dict(server=inst_dict)
def _build_image(self, response, inst):
+ ''' Returns the image sub-resource of a server '''
raise NotImplementedError()
def _build_flavor(self, response, inst):
+ ''' Returns the flavor sub-resource of a server '''
raise NotImplementedError()
class ViewBuilderV10(ViewBuilder):
+ ''' Models an Openstack API V1.0 server response '''
+
def _build_image(self, response, inst):
- if inst.get('image_id') != None:
- response['imageId'] = inst['image_id']
+ response['imageId'] = inst['image_id']
def _build_flavor(self, response, inst):
- if inst.get('instance_type') != None:
- response['flavorId'] = inst['instance_type']
+ response['flavorId'] = inst['instance_type']
class ViewBuilderV11(ViewBuilder):
+ ''' Models an Openstack API V1.0 server response '''
+
def __init__(self, addresses_builder, flavor_builder, image_builder):
ViewBuilder.__init__(self, addresses_builder)
self.flavor_builder = flavor_builder
self.image_builder = image_builder
def _build_image(self, response, inst):
- if inst.get('image_id') == None:
- return
image_id = inst["image_id"]
response["imageRef"] = self.image_builder.generate_href(image_id)
def _build_flavor(self, response, inst):
- if inst.get('instance_type') == None:
- return
flavor_id = inst["instance_type"]
response["flavorRef"] = self.flavor_builder.generate_href(flavor_id)
--
cgit
From 7ae8f5563c42d7c5dc67047dd9c42e982281d80b Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 16:53:43 +0100
Subject: Apparantly a more common problem than first thought.
---
nova/compute/manager.py | 8 ++++++--
nova/tests/test_compute.py | 14 +++++++++++---
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 576937cd8..67290c8dc 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -41,9 +41,10 @@ import string
import socket
import sys
import tempfile
-import time
import functools
+from eventlet import greenthread
+
from nova import exception
from nova import flags
from nova import log as logging
@@ -800,7 +801,7 @@ class ComputeManager(manager.Manager):
return self.driver.update_available_resource(context, self.host)
- def pre_live_migration(self, context, instance_id):
+ def pre_live_migration(self, context, instance_id, time=None):
"""Preparations for live migration at dest host.
:param context: security context
@@ -808,6 +809,9 @@ class ComputeManager(manager.Manager):
"""
+ if not time:
+ time = greenthread
+
# Getting instance info
instance_ref = self.db.instance_get(context, instance_id)
ec2_id = instance_ref['hostname']
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 3651f4cef..0209dd9ca 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -44,6 +44,14 @@ flags.DECLARE('stub_network', 'nova.compute.manager')
flags.DECLARE('live_migration_retry_count', 'nova.compute.manager')
+class FakeTime(object):
+ def __init__(self):
+ self.counter = 0
+
+ def sleep(self, t):
+ self.counter += t
+
+
class ComputeTestCase(test.TestCase):
"""Test case for compute"""
def setUp(self):
@@ -342,7 +350,7 @@ class ComputeTestCase(test.TestCase):
self.mox.ReplayAll()
self.assertRaises(exception.NotFound,
self.compute.pre_live_migration,
- c, instance_ref['id'])
+ c, instance_ref['id'], time=FakeTime())
def test_pre_live_migration_instance_has_volume(self):
"""Confirm setup_compute_volume is called when volume is mounted."""
@@ -395,7 +403,7 @@ class ComputeTestCase(test.TestCase):
self.compute.driver = drivermock
self.mox.ReplayAll()
- ret = self.compute.pre_live_migration(c, i_ref['id'])
+ ret = self.compute.pre_live_migration(c, i_ref['id'], time=FakeTime())
self.assertEqual(ret, None)
def test_pre_live_migration_setup_compute_node_fail(self):
@@ -428,7 +436,7 @@ class ComputeTestCase(test.TestCase):
self.mox.ReplayAll()
self.assertRaises(exception.ProcessExecutionError,
self.compute.pre_live_migration,
- c, i_ref['id'])
+ c, i_ref['id'], time=FakeTime())
def test_live_migration_works_correctly_with_volume(self):
"""Confirm check_for_export to confirm volume health check."""
--
cgit
From 06815cb729d8687403fc736ae6125c26867f42b3 Mon Sep 17 00:00:00 2001
From: Soren Hansen
Date: Tue, 22 Mar 2011 17:13:48 +0100
Subject: Remove unused global semaphore.
---
nova/utils.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/nova/utils.py b/nova/utils.py
index c580e805a..8b9ce4734 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -532,7 +532,6 @@ def loads(s):
return json.loads(s)
-_semaphores_semaphore = semaphore.Semaphore()
_semaphores = {}
--
cgit
From e648698bd171357228881a10d76e7853938e8feb Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Tue, 22 Mar 2011 17:00:36 +0000
Subject: Fix
---
nova/tests/test_localization.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py
index 393d71038..132a308fd 100644
--- a/nova/tests/test_localization.py
+++ b/nova/tests/test_localization.py
@@ -21,9 +21,9 @@ import sys
import unittest
import nova
+from nova import test
-
-class LocalizationTestCase(unittest.TestCase):
+class LocalizationTestCase(test.TestCase):
def test_multiple_positional_format_placeholders(self):
pat = re.compile("\W_\(")
single_pat = re.compile("\W%\W")
--
cgit
From 493e87976b7eb273f4115d46c91ad73671abb796 Mon Sep 17 00:00:00 2001
From: Naveed Massjouni
Date: Tue, 22 Mar 2011 13:18:08 -0400
Subject: Now using urlparse to parse a url to grab id out of it.
---
nova/api/openstack/common.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index b224cbfb4..99fba8fef 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -17,6 +17,7 @@
import re
from nova import exception
+from urlparse import urlparse
from webob import exc
import webob.exc
@@ -78,7 +79,7 @@ def get_image_id_from_image_hash(image_service, context, image_hash):
def get_id_from_href(href):
- m = re.match(r'http.+/.+/(\d)+$', href)
- if not m:
+ try:
+ return int(urlparse(href).path.split('/')[-1])
+ except:
raise exc.HTTPBadRequest(_('could not parse id from href'))
- return int(m.group(1))
--
cgit
From 116c0d52d21ebd6ed55a61467aac5d8c06a4b086 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Tue, 22 Mar 2011 17:46:17 +0000
Subject: Merge stuff
---
nova/api/openstack/servers.py | 4 ++--
nova/api/openstack/views/servers.py | 5 +++--
nova/compute/api.py | 8 ++++----
nova/db/sqlalchemy/api.py | 4 ++--
nova/virt/xenapi/vmops.py | 4 ++--
5 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index db5942e92..f3367e118 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -36,7 +36,7 @@ from nova.api.openstack.views import addresses as addresses_views
from nova.auth import manager as auth_manager
from nova.compute import instance_types
from nova.compute import power_state
-prom nova.quota import QuotaError
+from nova.quota import QuotaError
import nova.api.openstack
@@ -44,7 +44,7 @@ LOG = logging.getLogger('server')
FLAGS = flags.FLAGS
-plass Controller(wsgi.Controller):
+class Controller(wsgi.Controller):
""" The Server API controller for the OpenStack API """
_serialization_metadata = {
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 6d54a7a7e..9fd25999a 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -89,8 +89,9 @@ class ViewBuilder(object):
migration = db.migration_get_by_instance_and_status(ctxt,
inst['id'], 'finished')
inst_dict['status'] = 'resize-confirm'
- except Exception, e:
- inst_dict['status'] = power_mapping[inst_dict['status']]
+ except:
+ pass
+
inst_dict['addresses'] = self.addresses_builder.build(inst)
# Return the metadata as a dictionary
diff --git a/nova/compute/api.py b/nova/compute/api.py
index dbf99e7c5..748aba004 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -489,15 +489,15 @@ class API(base.Base):
def resize(self, context, instance_id, flavor_id):
"""Resize a running instance."""
instance = self.db.instance_get(context, instance_id)
- LOG.debug(_("Resizing instance %(instance_type['name'] to flavor"
- "%(flavor_id)") % locals())
current_instance_type = self.db.instance_type_get_by_name(
context, instance['instance_type'])
new_instance_type = self.db.instance_type_get_by_flavor_id(
context, flavor_id)
- LOG.debug(_("Old instance type %s -> New instance type %s"),
- (current_instance_type['name'], new_instance_type['name']))
+ current_instance_type_name = current_instance_type['name']
+ new_instance_type_name = new_instance_type['name']
+ LOG.debug(_("Old instance type %(current_instance_type_name)s, "
+ " new instance type %(new_instance_type_name)s") % locals())
if not new_instance_type:
raise exception.ApiError(_("Requested flavor does not exist"))
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index ac7f7cbf1..98810cb48 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2220,8 +2220,8 @@ def migration_get_by_instance_and_status(context, instance_id, status):
filter_by(instance_id=instance_id).\
filter_by(status=status).first()
if not result:
- raise exception.NotFound(_("No migration found for instance %s"
- "with status %s" % (instance_id, status)))
+ raise exception.NotFound(_("No migration found for instance "
+ "%(instance_id) with status %(status)") % locals())
return result
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 1f5d2d155..c1a65c997 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -387,8 +387,8 @@ class VMOps(object):
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
- LOG.debug(_("Resizing VDI %s for instance %s. Expanding to %sGB"),
- (vdi_uuid, instance.name, instance.local_gb))
+ LOG.debug(_("Resizing VDI %(vdi_uuid) for instance %(instance.name). "
+ "Expanding to %(instance.local_gb)GB") % locals())
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
LOG.debug(_("Resize instance %s complete") % (instance.name))
--
cgit
From 3b3889a19c4efa8dc917f772613543780f361df3 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Tue, 22 Mar 2011 17:55:40 +0000
Subject: tweak
---
nova/virt/xenapi/vmops.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index c1a65c997..8ac944966 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -387,8 +387,8 @@ class VMOps(object):
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
- LOG.debug(_("Resizing VDI %(vdi_uuid) for instance %(instance.name). "
- "Expanding to %(instance.local_gb)GB") % locals())
+ LOG.debug(_("Resizing VDI %(vdi_uuid) for instance %(instance.name)s. "
+ "Expanding to %(instance.local_gb)f GB") % locals())
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
LOG.debug(_("Resize instance %s complete") % (instance.name))
--
cgit
From 4c76bcc12954734d19afcb5e4519e35c23e39d6d Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Tue, 22 Mar 2011 18:04:09 +0000
Subject: tweak
---
nova/virt/xenapi/vmops.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 8ac944966..383096d63 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -387,8 +387,10 @@ class VMOps(object):
#The new disk size must be in bytes
new_disk_size = str(instance.local_gb * 1024 * 1024 * 1024)
- LOG.debug(_("Resizing VDI %(vdi_uuid) for instance %(instance.name)s. "
- "Expanding to %(instance.local_gb)f GB") % locals())
+ instance_name = instance.name
+ instance_local_gb = instance.local_gb
+ LOG.debug(_("Resizing VDI %(vdi_uuid)s for instance %(instance_name)s."
+ " Expanding to %(instance_local_gb)d GB") % locals())
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
self._session.call_xenapi('VDI.resize_online', vdi_ref, new_disk_size)
LOG.debug(_("Resize instance %s complete") % (instance.name))
--
cgit
From 8792383dfbd630388e6a51a76910e73203a3793f Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Tue, 22 Mar 2011 18:24:00 +0000
Subject: Tweak
---
nova/api/openstack/views/servers.py | 4 ++++
.../sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py | 1 +
nova/tests/test_localization.py | 1 +
3 files changed, 6 insertions(+)
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 9fd25999a..709052f22 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -16,7 +16,10 @@
# under the License.
import hashlib
+
from nova.compute import power_state
+import nova.context
+from nova import db
from nova.api.openstack import common
from nova.api.openstack.views import addresses as addresses_view
from nova.api.openstack.views import flavors as flavors_view
@@ -86,6 +89,7 @@ class ViewBuilder(object):
inst_dict['status'] = power_mapping[inst_dict['status']]
try:
+ ctxt = nova.context.get_admin_context()
migration = db.migration_get_by_instance_and_status(ctxt,
inst['id'], 'finished')
inst_dict['status'] = 'resize-confirm'
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
index e677ba14d..3fb92e85c 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
@@ -43,6 +43,7 @@ def upgrade(migrate_engine):
migrations.create_column(old_flavor_id)
migrations.create_column(new_flavor_id)
+
def downgrade(migrate_engine):
meta.bind = migrate_engine
migrations.drop_column(old_flavor_id)
diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py
index 132a308fd..a25809a79 100644
--- a/nova/tests/test_localization.py
+++ b/nova/tests/test_localization.py
@@ -23,6 +23,7 @@ import unittest
import nova
from nova import test
+
class LocalizationTestCase(test.TestCase):
def test_multiple_positional_format_placeholders(self):
pat = re.compile("\W_\(")
--
cgit
From ca37b31d64f9c5cf32ca7e6015176ef36e702dce Mon Sep 17 00:00:00 2001
From: Naveed Massjouni
Date: Tue, 22 Mar 2011 16:04:27 -0400
Subject: Updating doc strings in accordance with PEP 257. Fixing order of
imports in common.py.
---
nova/api/openstack/__init__.py | 4 ++--
nova/api/openstack/common.py | 16 +++++++++++-----
nova/api/openstack/views/servers.py | 22 ++++++++++++----------
3 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 21d354f1c..5f9648210 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -131,7 +131,7 @@ class APIRouter(wsgi.Router):
class APIRouterV10(APIRouter):
- ''' Defines routes specific to OpenStack API V1.0 '''
+ """Define routes specific to OpenStack API V1.0."""
def _setup_routes(self, mapper):
APIRouter._setup_routes(self, mapper)
@@ -142,7 +142,7 @@ class APIRouterV10(APIRouter):
class APIRouterV11(APIRouter):
- ''' Defines routes specific to OpenStack API V1.1 '''
+ """Define routes specific to OpenStack API V1.1."""
def _setup_routes(self, mapper):
APIRouter._setup_routes(self, mapper)
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index 99fba8fef..21ceec45e 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -15,11 +15,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-import re
-from nova import exception
from urlparse import urlparse
-from webob import exc
-import webob.exc
+
+import webob
+
+from nova import exception
def limited(items, request, max_limit=1000):
@@ -79,7 +79,13 @@ def get_image_id_from_image_hash(image_service, context, image_hash):
def get_id_from_href(href):
+ """Return the id portion of a url.
+
+ Given: http://www.foo.com/bar/123?q=4
+ Returns: 4
+
+ """
try:
return int(urlparse(href).path.split('/')[-1])
except:
- raise exc.HTTPBadRequest(_('could not parse id from href'))
+ raise webob.exc.HTTPBadRequest(_('could not parse id from href'))
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 3100c46b5..fad361bd4 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -25,27 +25,29 @@ from nova import utils
class ViewBuilder(object):
- '''
- Models a server response as a python dictionary.
+ """Model a server response as a python dictionary.
+
+ Public methods: build
Abstract methods: _build_image, _build_flavor
- '''
+
+ """
def __init__(self, addresses_builder):
self.addresses_builder = addresses_builder
def build(self, inst, is_detail):
- ''' Returns a dict that represenst a server '''
+ """Return a dict that represenst a server."""
if is_detail:
return self._build_detail(inst)
else:
return self._build_simple(inst)
def _build_simple(self, inst):
- ''' Returns a simple model of a server '''
+ """Return a simple model of a server."""
return dict(server=dict(id=inst['id'], name=inst['display_name']))
def _build_detail(self, inst):
- ''' Returns a detailed model of a server '''
+ """Returns a detailed model of a server."""
power_mapping = {
None: 'build',
power_state.NOSTATE: 'build',
@@ -80,16 +82,16 @@ class ViewBuilder(object):
return dict(server=inst_dict)
def _build_image(self, response, inst):
- ''' Returns the image sub-resource of a server '''
+ """Return the image sub-resource of a server."""
raise NotImplementedError()
def _build_flavor(self, response, inst):
- ''' Returns the flavor sub-resource of a server '''
+ """Return the flavor sub-resource of a server."""
raise NotImplementedError()
class ViewBuilderV10(ViewBuilder):
- ''' Models an Openstack API V1.0 server response '''
+ """Model an Openstack API V1.0 server response."""
def _build_image(self, response, inst):
response['imageId'] = inst['image_id']
@@ -99,7 +101,7 @@ class ViewBuilderV10(ViewBuilder):
class ViewBuilderV11(ViewBuilder):
- ''' Models an Openstack API V1.0 server response '''
+ """Model an Openstack API V1.0 server response."""
def __init__(self, addresses_builder, flavor_builder, image_builder):
ViewBuilder.__init__(self, addresses_builder)
--
cgit
From d06bce4b64b57551a722688a4038a4eaffa34278 Mon Sep 17 00:00:00 2001
From: Todd Willey
Date: Tue, 22 Mar 2011 16:34:02 -0400
Subject: typo fix.
---
nova/api/ec2/admin.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index d9a4ef999..f32d0804f 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -60,7 +60,7 @@ def project_dict(project):
def host_dict(host, compute_service, instances, volume_service, volumes, now):
"""Convert a host model object to a result dict"""
- rv = {'hostanme': host, 'instance_count': len(instances),
+ rv = {'hostname': host, 'instance_count': len(instances),
'volume_count': len(volumes)}
if compute_service:
latest = compute_service['updated_at'] or compute_service['created_at']
--
cgit
From 0dc2140d645d94d585fa8e3e5d189cd776574d28 Mon Sep 17 00:00:00 2001
From: Koji Iida
Date: Wed, 23 Mar 2011 13:14:54 +0900
Subject: Fix to avoid db migration failure in virtualenv
---
nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
index 8c9cf3377..e87085668 100644
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
+++ b/nova/db/sqlalchemy/migrate_repo/versions/012_add_ipv6_flatmanager.py
@@ -26,6 +26,9 @@ meta = MetaData()
# Just for the ForeignKey and column creation to succeed, these are not the
# actual definitions of instances or services.
#
+instances = Table('instances', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
#
# Tables to alter
--
cgit
From 3796b5a8fc2baa9a35ebbc721735f22e952e6aa3 Mon Sep 17 00:00:00 2001
From: Todd Willey
Date: Wed, 23 Mar 2011 00:31:50 -0400
Subject: Fix some crypto strangeness (\n in file_name field of certificates,
wrong IMPL method for certificate_update).
---
nova/crypto.py | 3 ++-
nova/db/api.py | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/nova/crypto.py b/nova/crypto.py
index 2a8d4abca..b112e5b92 100644
--- a/nova/crypto.py
+++ b/nova/crypto.py
@@ -26,6 +26,7 @@ import gettext
import hashlib
import os
import shutil
+import string
import struct
import tempfile
import time
@@ -267,7 +268,7 @@ def _sign_csr(csr_text, ca_folder):
'./openssl.cnf', '-infiles', inbound)
out, _err = utils.execute('openssl', 'x509', '-in', outbound,
'-serial', '-noout')
- serial = out.rpartition("=")[2]
+ serial = string.strip(out.rpartition("=")[2])
os.chdir(start)
with open(outbound, "r") as crtfile:
return (serial, crtfile.read())
diff --git a/nova/db/api.py b/nova/db/api.py
index add5bd83e..afc1bff2f 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -214,7 +214,7 @@ def certificate_update(context, certificate_id, values):
Raises NotFound if service does not exist.
"""
- return IMPL.service_update(context, certificate_id, values)
+ return IMPL.certificate_update(context, certificate_id, values)
###################
--
cgit
From 365b98f4d52740ef85f8a8f098a32e441d7ac168 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 21:42:17 -0700
Subject: Renamed check_instance -> check_isinstance to make intent clearer
---
nova/utils.py | 2 +-
nova/virt/connection.py | 2 +-
nova/virt/fake.py | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/nova/utils.py b/nova/utils.py
index e93f489be..2e653bda0 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -587,7 +587,7 @@ def get_from_path(items, path):
return get_from_path(results, remainder)
-def check_instance(obj, cls):
+def check_isinstance(obj, cls):
"""Checks that obj is of type cls, and lets PyLint infer types"""
if isinstance(obj, cls):
return obj
diff --git a/nova/virt/connection.py b/nova/virt/connection.py
index d585b6c21..4ba31c7a7 100644
--- a/nova/virt/connection.py
+++ b/nova/virt/connection.py
@@ -74,4 +74,4 @@ def get_connection(read_only=False):
if conn is None:
LOG.error(_('Failed to open connection to the hypervisor'))
sys.exit(1)
- return utils.check_instance(conn, driver.ComputeDriver)
+ return utils.check_isinstance(conn, driver.ComputeDriver)
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index e0e2369c7..57b02e00b 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -100,7 +100,7 @@ class FakeConnection(driver.ComputeDriver):
return self.instances.keys()
def _map_to_instance_info(self, instance):
- instance = utils.check_instance(instance, FakeInstance)
+ instance = utils.check_isinstance(instance, FakeInstance)
info = driver.InstanceInfo(instance.name, instance.state)
return info
--
cgit
From c8e8b44ef27e49b3986659ee0cb6bd77b38430d8 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 22:01:39 -0700
Subject: Forgot this in the rename of check_instance -> check_isinstance
---
nova/compute/manager.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 019bb3c89..b21f0b836 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -117,7 +117,7 @@ class ComputeManager(manager.Manager):
# and redocument the module docstring
if not compute_driver:
compute_driver = FLAGS.compute_driver
- self.driver = utils.check_instance(utils.import_object(
+ self.driver = utils.check_isinstance(utils.import_object(
compute_driver),
driver.ComputeDriver)
self.network_manager = utils.import_object(FLAGS.network_manager)
--
cgit
From 19da125805eedbfcfd202abac4a90c57e6c538c4 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 22:38:37 -0700
Subject: Filled out the base-driver contract, so it's not a false-promise
---
nova/compute/driver.py | 38 --------
nova/compute/manager.py | 3 +-
nova/virt/driver.py | 228 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+), 39 deletions(-)
delete mode 100644 nova/compute/driver.py
create mode 100644 nova/virt/driver.py
diff --git a/nova/compute/driver.py b/nova/compute/driver.py
deleted file mode 100644
index bda82c60a..000000000
--- a/nova/compute/driver.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Justin Santa Barbara
-# 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.
-
-"""
-Driver base-classes:
-
- (Beginning of) the contract that compute drivers must follow, and shared
- types that support that contract
-"""
-
-from nova.compute import power_state
-
-
-class InstanceInfo(object):
- def __init__(self, name, state):
- self.name = name
- assert state in power_state.valid_states()
- self.state = state
-
-
-class ComputeDriver(object):
- def list_instances_detail(self):
- """Return a list of InstanceInfo for all registered VMs"""
- raise NotImplementedError()
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index b21f0b836..f37651ea6 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -52,7 +52,7 @@ from nova import manager
from nova import rpc
from nova import utils
from nova.compute import power_state
-from nova.compute import driver
+from nova.virt import driver
FLAGS = flags.FLAGS
flags.DEFINE_string('instances_path', '$state_path/instances',
@@ -441,6 +441,7 @@ class ComputeManager(manager.Manager):
#TODO(mdietz): we may want to split these into separate methods.
if migration_ref['source_compute'] == FLAGS.host:
+ #NOTE(justinsb): Naughty calling of internal method
self.driver._start(instance_ref)
self.db.migration_update(context, migration_id,
{'status': 'reverted'})
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
new file mode 100644
index 000000000..6c1b97ce9
--- /dev/null
+++ b/nova/virt/driver.py
@@ -0,0 +1,228 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# 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.
+
+"""
+Driver base-classes:
+
+ (Beginning of) the contract that compute drivers must follow, and shared
+ types that support that contract
+"""
+
+from nova.compute import power_state
+
+
+class InstanceInfo(object):
+ def __init__(self, name, state):
+ self.name = name
+ assert state in power_state.valid_states()
+ self.state = state
+
+
+class ComputeDriver(object):
+ """Base class for compute drivers."""
+
+ def init_host(self, host):
+ """Adopt existing VM's running here"""
+ raise NotImplementedError()
+
+ def get_info(self, instance_name):
+ """Get the current status of an instance, by name (not ID!)
+
+ Returns a dict containing:
+ :state: the running state, one of the power_state codes
+ :max_mem: (int) the maximum memory in KBytes allowed
+ :mem: (int) the memory in KBytes used by the domain
+ :num_cpu: (int) the number of virtual CPUs for the domain
+ :cpu_time: (int) the CPU time used in nanoseconds
+ """
+ raise NotImplementedError()
+
+ def list_instances(self):
+ raise NotImplementedError()
+
+ def list_instances_detail(self):
+ """Return a list of InstanceInfo for all registered VMs"""
+ raise NotImplementedError()
+
+ def spawn(self, instance):
+ """Launch a VM for the specified instance"""
+ raise NotImplementedError()
+
+ def destroy(self, instance, cleanup=True):
+ """Shutdown specified VM"""
+ raise NotImplementedError()
+
+ def reboot(self, instance):
+ """Reboot specified VM"""
+ raise NotImplementedError()
+
+ def snapshot_instance(self, context, instance_id, image_id):
+ raise NotImplementedError()
+
+ def get_console_pool_info(self, console_type):
+ """???
+
+ Returns a dict containing:
+ :address: ???
+ :username: ???
+ :password: ???
+ """
+ raise NotImplementedError()
+
+ def get_console_output(self, instance):
+ raise NotImplementedError()
+
+ def get_ajax_console(self, instance):
+ raise NotImplementedError()
+
+ def get_diagnostics(self, instance):
+ """Return data about VM diagnostics"""
+ raise NotImplementedError()
+
+ def get_host_ip_addr(self):
+ raise NotImplementedError()
+
+ def attach_volume(self, context, instance_id, volume_id, mountpoint):
+ raise NotImplementedError()
+
+ def detach_volume(self, context, instance_id, volume_id):
+ raise NotImplementedError()
+
+ def compare_cpu(self, context, cpu_info):
+ raise NotImplementedError()
+
+ def migrate_disk_and_power_off(self, instance, dest):
+ """Transfers the VHD of a running instance to another host, then shuts
+ off the instance copies over the COW disk"""
+ raise NotImplementedError()
+
+ def snapshot(self, instance, image_id):
+ """ Create snapshot from a running VM instance """
+ raise NotImplementedError()
+
+ def finish_resize(self, instance, disk_info):
+ """Completes a resize, turning on the migrated instance"""
+ raise NotImplementedError()
+
+ def pause(self, instance, callback):
+ """Pause VM instance"""
+ raise NotImplementedError()
+
+ def unpause(self, instance, callback):
+ """Unpause paused VM instance"""
+ raise NotImplementedError()
+
+ def suspend(self, instance, callback):
+ """suspend the specified instance"""
+ raise NotImplementedError()
+
+ def resume(self, instance, callback):
+ """resume the specified instance"""
+ raise NotImplementedError()
+
+ def rescue(self, instance, callback):
+ """Rescue the specified instance"""
+ raise NotImplementedError()
+
+ def unrescue(self, instance, callback):
+ """Unrescue the specified instance"""
+ raise NotImplementedError()
+
+ def update_available_resource(self, ctxt, host):
+ """Updates compute manager resource info on ComputeNode table.
+
+ This method is called when nova-compute launches, and
+ whenever admin executes "nova-manage service update_resource".
+
+ :param ctxt: security context
+ :param host: hostname that compute manager is currently running
+
+ """
+ raise NotImplementedError()
+
+ def live_migration(self, ctxt, instance_ref, dest,
+ post_method, recover_method):
+ """Spawning live_migration operation for distributing high-load.
+
+ :params ctxt: security context
+ :params instance_ref:
+ nova.db.sqlalchemy.models.Instance object
+ instance object that is migrated.
+ :params dest: destination host
+ :params post_method:
+ post operation method.
+ expected nova.compute.manager.post_live_migration.
+ :params recover_method:
+ recovery method when any exception occurs.
+ expected nova.compute.manager.recover_live_migration.
+
+ """
+ raise NotImplementedError()
+
+ def refresh_security_group_rules(self, security_group_id):
+ raise NotImplementedError()
+
+ def refresh_security_group_members(self, security_group_id):
+ raise NotImplementedError()
+
+ def reset_network(self, instance):
+ """reset networking for specified instance"""
+ raise NotImplementedError()
+
+ def ensure_filtering_rules_for_instance(self, instance_ref):
+ """Setting up filtering rules and waiting for its completion.
+
+ To migrate an instance, filtering rules to hypervisors
+ and firewalls are inevitable on destination host.
+ ( Waiting only for filtering rules to hypervisor,
+ since filtering rules to firewall rules can be set faster).
+
+ Concretely, the below method must be called.
+ - setup_basic_filtering (for nova-basic, etc.)
+ - prepare_instance_filter(for nova-instance-instance-xxx, etc.)
+
+ to_xml may have to be called since it defines PROJNET, PROJMASK.
+ but libvirt migrates those value through migrateToURI(),
+ so , no need to be called.
+
+ Don't use thread for this method since migration should
+ not be started when setting-up filtering rules operations
+ are not completed.
+
+ :params instance_ref: nova.db.sqlalchemy.models.Instance object
+
+ """
+ raise NotImplementedError()
+
+ def unfilter_instance(self, instance):
+ """Stop filtering instance"""
+ raise NotImplementedError()
+
+ def set_admin_password(self, context, instance_id, new_pass=None):
+ """Set the root/admin password for an instance on this server."""
+ raise NotImplementedError()
+
+ def inject_file(self, instance, b64_path, b64_contents):
+ """Create a file on the VM instance. The file path and contents
+ should be base64-encoded.
+ """
+ raise NotImplementedError()
+
+ def inject_network_info(self, instance):
+ """inject network info for specified instance"""
+ raise NotImplementedError()
+
--
cgit
From a0432e417a13fd9579c40bdd54f0201b06470f45 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 22:42:12 -0700
Subject: Added note about the advantages of using a type vs using a set of
global constants
---
nova/compute/power_state.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py
index 145362f97..d304285b2 100644
--- a/nova/compute/power_state.py
+++ b/nova/compute/power_state.py
@@ -31,7 +31,9 @@ CRASHED = 0x06
SUSPENDED = 0x07
FAILED = 0x08
-#TODO(justinsb): Power state really needs to be a proper class...
+#TODO(justinsb): Power state really needs to be a proper class,
+# so that we're not locked into the libvirt status codes and can put mapping
+# logic here rather than spread throughout the code
_STATE_MAP = {
NOSTATE: 'pending',
RUNNING: 'running',
--
cgit
From a4d78e44d7ca35a6cca4454667cab743409fd95a Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 22:45:15 -0700
Subject: Added space in between # and TODO in #TODO
---
nova/compute/manager.py | 2 +-
nova/compute/power_state.py | 2 +-
nova/utils.py | 2 +-
nova/virt/hyperv.py | 2 +-
nova/virt/xenapi/vmops.py | 4 ++--
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index f37651ea6..cfd2b0ac4 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1032,6 +1032,6 @@ class ComputeManager(manager.Manager):
# Are there VMs not in the DB?
for vm_not_found_in_db in vms_not_found_in_db:
name = vm_not_found_in_db
- #TODO(justinsb): What to do here? Adopt it? Shut it down?
+ # TODO(justinsb): What to do here? Adopt it? Shut it down?
LOG.warning(_("Found VM not in DB: '%(name)s'. Ignoring")
% locals())
diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py
index d304285b2..ed50e492e 100644
--- a/nova/compute/power_state.py
+++ b/nova/compute/power_state.py
@@ -31,7 +31,7 @@ CRASHED = 0x06
SUSPENDED = 0x07
FAILED = 0x08
-#TODO(justinsb): Power state really needs to be a proper class,
+# TODO(justinsb): Power state really needs to be a proper class,
# so that we're not locked into the libvirt status codes and can put mapping
# logic here rather than spread throughout the code
_STATE_MAP = {
diff --git a/nova/utils.py b/nova/utils.py
index 2e653bda0..36b384f4f 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -592,5 +592,5 @@ def check_isinstance(obj, cls):
if isinstance(obj, cls):
return obj
raise Exception(_("Expected object of type: %s") % (str(cls)))
- #TODO(justinsb): Can we make this better??
+ # TODO(justinsb): Can we make this better??
return cls() # Ugly PyLint hack
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index 435272109..21e21ec13 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -127,7 +127,7 @@ class HyperVConnection(driver.ComputeDriver):
return vms
def list_instances_detail(self):
- #TODO(justinsb): This is a terrible implementation (1+N)
+ # TODO(justinsb): This is a terrible implementation (1+N)
instance_infos = []
for instance_name in self.list_instances():
info = self.get_info(instance_name)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 3a58a887e..6cd61a86f 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -73,7 +73,7 @@ class VMOps(object):
if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]:
name = vm_rec["name_label"]
- #TODO(justinsb): Yuk...
+ # TODO(justinsb): Yuk...
openstack_format = VMHelper.compile_info(vm_rec)
state = openstack_format['state']
@@ -932,7 +932,7 @@ class VMOps(object):
"""
vm_ref = self._get_vm_opaque_ref(instance_or_vm)
data = self._session.call_xenapi_request('VM.get_xenstore_data',
- (vm_ref, ))
+ (vm_ref,))
ret = {}
if keys is None:
keys = data.keys()
--
cgit
From 52c2bb5e7fadf12aae96d895d374990fd4990e29 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 22:49:22 -0700
Subject: Cleaned up comment about virsh domain.info() return format
---
nova/virt/libvirt_conn.py | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index e95bcac39..dfe0bca49 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -60,10 +60,10 @@ from nova import log as logging
#from nova import test
from nova import utils
from nova.auth import manager
-from nova.compute import driver
from nova.compute import instance_types
from nova.compute import power_state
from nova.virt import disk
+from nova.virt import driver
from nova.virt import images
libvirt = None
@@ -135,8 +135,8 @@ def get_connection(read_only):
def _late_load_cheetah():
global Template
if Template is None:
- t = __import__('Cheetah.Template', globals(), locals(), ['Template'],
- -1)
+ t = __import__('Cheetah.Template', globals(), locals(),
+ ['Template'], -1)
Template = t.Template
@@ -238,12 +238,15 @@ class LibvirtConnection(driver.ComputeDriver):
for x in self._conn.listDomainsID()]
def _map_to_instance_info(self, domain):
- # .info() returns a list of:
- #state: one of the state values (virDomainState)
- #maxMemory: the maximum memory used by the domain
- #memory: the current amount of memory used by the domain
- #nbVirtCPU: the number of virtual CPU
- #cpuTime: the time used by the domain in nanoseconds
+ """Gets info from a virsh domain object into an InstanceInfo"""
+
+ # domain.info() returns a list of:
+ # state: one of the state values (virDomainState)
+ # maxMemory: the maximum memory used by the domain
+ # memory: the current amount of memory used by the domain
+ # nbVirtCPU: the number of virtual CPU
+ # puTime: the time used by the domain in nanoseconds
+
(state, _max_mem, _mem, _num_cpu, _cpu_time) = domain.info()
name = domain.name()
--
cgit
From 95a32b4ae8d418576799fb9dd5d34e73728d7a1f Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 22:50:45 -0700
Subject: Clarified my "Yuk" comment
---
nova/virt/xenapi/vmops.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 6cd61a86f..a0c84c803 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -73,7 +73,7 @@ class VMOps(object):
if not vm_rec["is_a_template"] and not vm_rec["is_control_domain"]:
name = vm_rec["name_label"]
- # TODO(justinsb): Yuk...
+ # TODO(justinsb): This a roundabout way to map the state
openstack_format = VMHelper.compile_info(vm_rec)
state = openstack_format['state']
--
cgit
From 846b09925da07c2858052143d5fff4766a782cf1 Mon Sep 17 00:00:00 2001
From: Anthony Young
Date: Tue, 22 Mar 2011 22:54:34 -0700
Subject: Fix for lp740742 - format describe_instance_output correctly to
prevent errors in dashboard
---
nova/api/ec2/admin.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index 037184b40..d8d90ad83 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -120,7 +120,8 @@ class AdminController(object):
def describe_instance_types(self, context, **_kwargs):
"""Returns all active instance types data (vcpus, memory, etc.)"""
- return {'instanceTypeSet': [db.instance_type_get_all(context)]}
+ return {'instanceTypeSet': [instance_dict(v) for v in
+ db.instance_type_get_all(context).values()]}
def describe_user(self, _context, name, **_kwargs):
"""Returns user data, including access and secret keys."""
--
cgit
From b69a63c5d7458610b6e8931b4955c0b5b2b468f5 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Tue, 22 Mar 2011 22:58:52 -0700
Subject: Fixed up the new location of driver.py
---
nova/virt/driver.py | 5 ++++-
nova/virt/fake.py | 2 +-
nova/virt/hyperv.py | 2 +-
nova/virt/xenapi_conn.py | 2 +-
4 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index 6c1b97ce9..d01a91b93 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -33,7 +33,10 @@ class InstanceInfo(object):
class ComputeDriver(object):
- """Base class for compute drivers."""
+ """Base class for compute drivers.
+
+ Lots of documentation is currently on fake.py.
+ """
def init_host(self, host):
"""Adopt existing VM's running here"""
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 57b02e00b..5b0fe1877 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -27,8 +27,8 @@ semantics of real hypervisor connections.
from nova import exception
from nova import utils
-from nova.compute import driver
from nova.compute import power_state
+from nova.virt import driver
def get_connection(_):
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index 21e21ec13..bd45dfe0e 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -67,8 +67,8 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova.auth import manager
-from nova.compute import driver
from nova.compute import power_state
+from nova.virt import driver
from nova.virt import images
wmi = None
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 9390db0bb..b5bff6c26 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -69,7 +69,7 @@ from nova import db
from nova import utils
from nova import flags
from nova import log as logging
-from nova.compute import driver
+from nova.virt import driver
from nova.virt.xenapi.vmops import VMOps
from nova.virt.xenapi.volumeops import VolumeOps
--
cgit
From a822941d1fbfcfff7d52e2e42f2a50cb8aca6f0d Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 23 Mar 2011 01:02:13 -0700
Subject: Report the exception (happens when can't import libvirt)
---
nova/compute/manager.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 576937cd8..4f338135b 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -118,8 +118,8 @@ class ComputeManager(manager.Manager):
try:
self.driver = utils.import_object(compute_driver)
- except ImportError:
- LOG.error("Unable to load the virtualization driver.")
+ except ImportError as e:
+ LOG.error(_("Unable to load the virtualization driver: %s") % (e))
sys.exit(1)
self.network_manager = utils.import_object(FLAGS.network_manager)
--
cgit
From 3362be7e9f2feda33e14ab4fb7c6f70277df1cf5 Mon Sep 17 00:00:00 2001
From: Salvatore Orlando
Date: Wed, 23 Mar 2011 12:53:10 +0000
Subject: Checking whether cidr_v6 is not null before populating ipv6 key in
network info map (VMOps._get_network_info)
---
nova/virt/xenapi/vmops.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 499c6d8a1..b51489ebc 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -723,8 +723,9 @@ class VMOps(object):
'mac': instance.mac_address,
'rxtx_cap': flavor['rxtx_cap'],
'dns': [network['dns']],
- 'ips': [ip_dict(ip) for ip in network_IPs],
- 'ip6s': [ip6_dict(ip) for ip in network_IPs]}
+ 'ips': [ip_dict(ip) for ip in network_IPs]}
+ if network['cidr_v6']:
+ info['ip6s'] = [ip6_dict(ip) for ip in network_IPs]
network_info.append((network, info))
return network_info
--
cgit
From ea92a88b727814698dbc4ebf5dc705677d636445 Mon Sep 17 00:00:00 2001
From: Naveed Massjouni
Date: Wed, 23 Mar 2011 14:05:21 -0400
Subject: Using super to call parent _setup_routes in APIRouter subclasses.
---
nova/api/openstack/__init__.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 5f9648210..e68110bc4 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -134,7 +134,7 @@ class APIRouterV10(APIRouter):
"""Define routes specific to OpenStack API V1.0."""
def _setup_routes(self, mapper):
- APIRouter._setup_routes(self, mapper)
+ super(APIRouterV10, self)._setup_routes(mapper)
mapper.resource("server", "servers",
controller=servers.ControllerV10(),
collection={'detail': 'GET'},
@@ -145,7 +145,7 @@ class APIRouterV11(APIRouter):
"""Define routes specific to OpenStack API V1.1."""
def _setup_routes(self, mapper):
- APIRouter._setup_routes(self, mapper)
+ super(APIRouterV11, self)._setup_routes(mapper)
mapper.resource("server", "servers",
controller=servers.ControllerV11(),
collection={'detail': 'GET'},
--
cgit
From c3d47689a762bfa4aa38c7d4700bb1969d37d1d1 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Wed, 23 Mar 2011 18:56:23 +0000
Subject: merge prop changes
---
nova/api/openstack/views/servers.py | 9 +++------
nova/compute/api.py | 13 ++++++++++++-
nova/compute/manager.py | 8 ++++----
3 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 709052f22..a21a6e7ff 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -18,6 +18,7 @@
import hashlib
from nova.compute import power_state
+import nova.compute.api
import nova.context
from nova import db
from nova.api.openstack import common
@@ -87,14 +88,10 @@ class ViewBuilder(object):
for k, v in mapped_keys.iteritems():
inst_dict[k] = inst[v]
+ ctxt = nova.context.get_admin_context()
inst_dict['status'] = power_mapping[inst_dict['status']]
- try:
- ctxt = nova.context.get_admin_context()
- migration = db.migration_get_by_instance_and_status(ctxt,
- inst['id'], 'finished')
+ if nova.compute.api.has_finished_migration(ctxt, inst['id']):
inst_dict['status'] = 'resize-confirm'
- except:
- pass
inst_dict['addresses'] = self.addresses_builder.build(inst)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 748aba004..78110c048 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -253,6 +253,16 @@ class API(base.Base):
return [dict(x.iteritems()) for x in instances]
+ def has_finished_migration(self, context, instance_id):
+ """Retrieves whether or not a finished migration exists for
+ an instance"""
+ try:
+ db.migration_get_by_instance_and_status(ctxt, inst['id'],
+ 'finished')
+ return True
+ except Exception, e:
+ return False
+
def ensure_default_security_group(self, context):
""" Create security group for the security context if it
does not already exist
@@ -499,7 +509,8 @@ class API(base.Base):
LOG.debug(_("Old instance type %(current_instance_type_name)s, "
" new instance type %(new_instance_type_name)s") % locals())
if not new_instance_type:
- raise exception.ApiError(_("Requested flavor does not exist"))
+ raise exception.ApiError(_("Requested flavor %(flavor_id)d "
+ "does not exist") % locals())
if current_instance_type['memory_mb'] >= \
new_instance_type['memory_mb']:
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 78ef33ac2..ac63f68ea 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -458,8 +458,8 @@ class ComputeManager(manager.Manager):
instance_type = self.db.instance_type_get_by_flavor_id(context,
migration_ref['old_flavor_id'])
- #Just roll back the record. There's no need to resize down since
- #the 'old' VM already has the preferred attributes
+ # Just roll back the record. There's no need to resize down since
+ # the 'old' VM already has the preferred attributes
self.db.instance_update(context, instance_id,
dict(memory_mb=instance_type['memory_mb'],
vcpus=instance_type['vcpus'],
@@ -536,8 +536,8 @@ class ComputeManager(manager.Manager):
migration_ref = self.db.migration_get(context, migration_id)
instance_ref = self.db.instance_get(context,
migration_ref['instance_id'])
- #TODO(mdietz): apply the rest of the instance_type attributes going
- #after they're supported
+ # TODO(mdietz): apply the rest of the instance_type attributes going
+ # after they're supported
instance_type = self.db.instance_type_get_by_flavor_id(context,
migration_ref['new_flavor_id'])
self.db.instance_update(context, instance_id,
--
cgit
From 1aa576ee43cdf6520df6b5c8429f8d426bafc72a Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Wed, 23 Mar 2011 18:59:24 +0000
Subject: Moving the migration yet again
---
.../versions/012_add_flavors_to_migrations.py | 50 ----------------------
.../versions/013_add_flavors_to_migrations.py | 50 ++++++++++++++++++++++
2 files changed, 50 insertions(+), 50 deletions(-)
delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/013_add_flavors_to_migrations.py
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
deleted file mode 100644
index 3fb92e85c..000000000
--- a/nova/db/sqlalchemy/migrate_repo/versions/012_add_flavors_to_migrations.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# 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.from sqlalchemy import *
-
-from sqlalchemy import *
-from migrate import *
-
-from nova import log as logging
-
-
-meta = MetaData()
-
-migrations = Table('migrations', meta,
- Column('id', Integer(), primary_key=True, nullable=False),
- )
-
-#
-# Tables to alter
-#
-#
-
-old_flavor_id = Column('old_flavor_id', Integer())
-new_flavor_id = Column('new_flavor_id', Integer())
-
-
-def upgrade(migrate_engine):
- # Upgrade operations go here. Don't create your own engine;
- # bind migrate_engine to your metadata
- meta.bind = migrate_engine
- migrations.create_column(old_flavor_id)
- migrations.create_column(new_flavor_id)
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
- migrations.drop_column(old_flavor_id)
- migrations.drop_column(new_flavor_id)
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/013_add_flavors_to_migrations.py b/nova/db/sqlalchemy/migrate_repo/versions/013_add_flavors_to_migrations.py
new file mode 100644
index 000000000..3fb92e85c
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/013_add_flavors_to_migrations.py
@@ -0,0 +1,50 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.from sqlalchemy import *
+
+from sqlalchemy import *
+from migrate import *
+
+from nova import log as logging
+
+
+meta = MetaData()
+
+migrations = Table('migrations', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+#
+# Tables to alter
+#
+#
+
+old_flavor_id = Column('old_flavor_id', Integer())
+new_flavor_id = Column('new_flavor_id', Integer())
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+ migrations.create_column(old_flavor_id)
+ migrations.create_column(new_flavor_id)
+
+
+def downgrade(migrate_engine):
+ meta.bind = migrate_engine
+ migrations.drop_column(old_flavor_id)
+ migrations.drop_column(new_flavor_id)
--
cgit
From 5a5c7d22e7a00c9a3b34f8c08db70b644eee2d92 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Wed, 23 Mar 2011 19:16:03 +0000
Subject: Unit test cleanup
---
nova/api/openstack/views/servers.py | 5 +++--
nova/compute/api.py | 2 +-
nova/db/sqlalchemy/api.py | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index a21a6e7ff..18d31a29d 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -18,7 +18,7 @@
import hashlib
from nova.compute import power_state
-import nova.compute.api
+import nova.compute
import nova.context
from nova import db
from nova.api.openstack import common
@@ -90,7 +90,8 @@ class ViewBuilder(object):
ctxt = nova.context.get_admin_context()
inst_dict['status'] = power_mapping[inst_dict['status']]
- if nova.compute.api.has_finished_migration(ctxt, inst['id']):
+ compute_api = nova.compute.API()
+ if compute_api.has_finished_migration(ctxt, inst['id']):
inst_dict['status'] = 'resize-confirm'
inst_dict['addresses'] = self.addresses_builder.build(inst)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 78110c048..c2738f6f5 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -257,7 +257,7 @@ class API(base.Base):
"""Retrieves whether or not a finished migration exists for
an instance"""
try:
- db.migration_get_by_instance_and_status(ctxt, inst['id'],
+ db.migration_get_by_instance_and_status(context, instance_id,
'finished')
return True
except Exception, e:
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 98810cb48..d7b5aff46 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -2221,7 +2221,7 @@ def migration_get_by_instance_and_status(context, instance_id, status):
filter_by(status=status).first()
if not result:
raise exception.NotFound(_("No migration found for instance "
- "%(instance_id) with status %(status)") % locals())
+ "%(instance_id)s with status %(status)s") % locals())
return result
--
cgit
From abb764f51385a0b811b23379d78f7db027d4cca5 Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Wed, 23 Mar 2011 14:41:35 -0500
Subject: Automatically unrescue instances after a given timeout
---
nova/compute/manager.py | 12 +++++-
nova/utils.py | 7 ++++
nova/virt/libvirt_conn.py | 4 ++
nova/virt/xenapi/vmops.py | 95 +++++++++++++++++++++++++++++++++++------------
nova/virt/xenapi_conn.py | 4 ++
5 files changed, 96 insertions(+), 26 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 576937cd8..3834c33ab 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -65,8 +65,11 @@ flags.DEFINE_string('console_host', socket.gethostname(),
'Console proxy host to use to connect to instances on'
'this host.')
flags.DEFINE_integer('live_migration_retry_count', 30,
- ("Retry count needed in live_migration."
- " sleep 1 sec for each count"))
+ "Retry count needed in live_migration."
+ " sleep 1 sec for each count")
+flags.DEFINE_integer("rescue_timeout", 0,
+ "Automatically unrescue an instance after N hours."
+ " Set to 0 to disable.")
LOG = logging.getLogger('nova.compute.manager')
@@ -132,6 +135,11 @@ class ComputeManager(manager.Manager):
"""
self.driver.init_host(host=self.host)
+ def periodic_tasks(self, context=None):
+ """Tasks to be run at a periodic interval."""
+ super(ComputeManager, self).periodic_tasks(context)
+ self.driver.poll_rescued_instances(FLAGS.rescue_timeout)
+
def _update_state(self, context, instance_id):
"""Update the state of an instance from the driver info."""
# FIXME(ja): include other fields from state?
diff --git a/nova/utils.py b/nova/utils.py
index 499af2039..38cdb8021 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -334,6 +334,13 @@ def utcnow():
utcnow.override_time = None
+def is_then_greater(then, seconds):
+ if utcnow() - then > datetime.timedelta(seconds=seconds):
+ return True
+ else:
+ return False
+
+
def utcnow_ts():
"""Timestamp version of our utcnow function."""
return time.mktime(utcnow().timetuple())
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index e80b9fbdf..07545382d 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -412,6 +412,10 @@ class LibvirtConnection(object):
# the normal xml file, we can just call reboot here
self.reboot(instance)
+ @exception.wrap_exception
+ def poll_rescued_instances(self, timeout):
+ pass
+
@exception.wrap_exception
def spawn(self, instance):
xml = self.to_xml(instance)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 61ff00903..f46ac3b7e 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -51,6 +51,7 @@ class VMOps(object):
def __init__(self, session):
self.XenAPI = session.get_imported_xenapi()
self._session = session
+ self.poll_rescue_last_ran = None
VMHelper.XenAPI = self.XenAPI
@@ -462,6 +463,10 @@ class VMOps(object):
except self.XenAPI.Failure, exc:
LOG.exception(exc)
+ def _shutdown_rescue(self, vm_ref):
+ """Shutdown a rescue instance"""
+ self._session.call_xenapi("Async.VM.hard_shutdown", rescue_vm_ref)
+
def _destroy_vdis(self, instance, vm_ref):
"""Destroys all VDIs associated with a VM"""
instance_id = instance.id
@@ -479,6 +484,24 @@ class VMOps(object):
except self.XenAPI.Failure, exc:
LOG.exception(exc)
+ def _destroy_rescue_vdis(self, rescue_vm_ref):
+ """Destroys all VDIs associated with a rescued VM"""
+ vdi_refs = VMHelper.lookup_vm_vdis(self._session, rescue_vm_ref)
+ for vdi_ref in vdi_refs:
+ try:
+ self._session.call_xenapi("Async.VDI.destroy", vdi_ref)
+ except self.XenAPI.Failure:
+ continue
+
+ def _destroy_rescue_vbds(self, rescue_vm_ref):
+ """Destroys all VBDs tied to a rescue VM"""
+ vbd_refs = self._session.get_xenapi().VM.get_VBDs(rescue_vm_ref)
+ for vbd_ref in vbd_refs:
+ _vbd_ref = self._session.get_xenapi().VBD.get_record(vbd_ref)
+ if _vbd_ref["userdevice"] == "1":
+ VMHelper.unplug_vbd(self._session, vbd_ref)
+ VMHelper.destroy_vbd(self._session, vbd_ref)
+
def _destroy_kernel_ramdisk(self, instance, vm_ref):
"""
Three situations can occur:
@@ -529,6 +552,10 @@ class VMOps(object):
LOG.debug(_("Instance %(instance_id)s VM destroyed") % locals())
+ def _destroy_rescue(self, vm_ref):
+ """Destroy a rescue instance"""
+ self._session.call_xenapi("Async.VM.destroy", rescue_vm_ref)
+
def destroy(self, instance):
"""
Destroy VM instance
@@ -632,41 +659,61 @@ class VMOps(object):
"""
rescue_vm_ref = VMHelper.lookup(self._session,
- instance.name + "-rescue")
+ instance.name + "-rescue")
if not rescue_vm_ref:
raise exception.NotFound(_(
"Instance is not in Rescue Mode: %s" % instance.name))
original_vm_ref = self._get_vm_opaque_ref(instance)
- vbd_refs = self._session.get_xenapi().VM.get_VBDs(rescue_vm_ref)
-
instance._rescue = False
- for vbd_ref in vbd_refs:
- _vbd_ref = self._session.get_xenapi().VBD.get_record(vbd_ref)
- if _vbd_ref["userdevice"] == "1":
- VMHelper.unplug_vbd(self._session, vbd_ref)
- VMHelper.destroy_vbd(self._session, vbd_ref)
-
- task1 = self._session.call_xenapi("Async.VM.hard_shutdown",
- rescue_vm_ref)
- self._session.wait_for_task(task1, instance.id)
-
- vdi_refs = VMHelper.lookup_vm_vdis(self._session, rescue_vm_ref)
- for vdi_ref in vdi_refs:
- try:
- task = self._session.call_xenapi('Async.VDI.destroy', vdi_ref)
- self._session.wait_for_task(task, instance.id)
- except self.XenAPI.Failure:
- continue
-
- task2 = self._session.call_xenapi('Async.VM.destroy', rescue_vm_ref)
- self._session.wait_for_task(task2, instance.id)
-
+ self._destroy_rescue_vbds(rescue_vm_ref)
+ self._shutdown_rescue(rescue_vm_ref)
+ self._destroy_rescue_vdis(rescue_vm_ref)
+ self._destroy_rescue(rescue_vm_ref)
self._release_bootlock(original_vm_ref)
self._start(instance, original_vm_ref)
+ def poll_rescued_instances(self, timeout):
+ """Look for expirable rescued instances
+ - forcibly exit rescue mode for any instances that have been
+ in rescue mode for >= the provided timeout
+ """
+ last_ran = self.poll_rescue_last_ran
+ if last_ran:
+ if not utils.is_then_greater(last_ran, timeout * 60 * 60):
+ # Do not run. Let's bail.
+ return
+ else:
+ # Update the time tracker and proceed.
+ self.poll_rescue_last_ran = utils.utcnow()
+ else:
+ # We need a base time to start tracking.
+ self.poll_rescue_last_ran = utils.utcnow()
+ return
+
+ vms = []
+ for instance in self.list_instances():
+ if instance.endswith("-rescue"):
+ vms.append(dict(name=instance,
+ vm_ref=VMHelper.lookup(self._session,
+ instance)))
+
+ for vm in vms:
+ rescue_name = vm["name"]
+ rescue_vm_ref = vm["vm_ref"]
+ original_name = vm["name"].split("-rescue", 1)[0]
+ original_vm_ref = VMHelper.lookup(self._session, original_name)
+
+ self._destroy_rescue_vbds(rescue_vm_ref)
+ self._shutdown_rescue(rescue_vm_ref)
+ self._destroy_rescue_vdis(rescue_vm_ref)
+ self._destroy_rescue(rescue_vm_ref)
+ self._release_bootlock(original_vm_ref)
+ self._session.call_xenapi("VM.start", original_vm_ref, False,
+ False)
+
def get_info(self, instance):
"""Return data about VM instance"""
vm_ref = self._get_vm_opaque_ref(instance)
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index da42a83b6..50aad96b8 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -225,6 +225,10 @@ class XenAPIConnection(object):
"""Unrescue the specified instance"""
self._vmops.unrescue(instance, callback)
+ def poll_rescued_instances(self, timeout):
+ """Poll for rescued instances"""
+ self._vmops.poll_rescued_instances(timeout)
+
def reset_network(self, instance):
"""reset networking for specified instance"""
self._vmops.reset_network(instance)
--
cgit
From 8eab4f6ecaf51221b335e76d9e532a1f159c2f2d Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Wed, 23 Mar 2011 19:44:32 +0000
Subject: Forgot extraneous module import
---
nova/api/openstack/servers.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index f3367e118..d392ab57f 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -23,7 +23,6 @@ from webob import exc
from nova import compute
from nova import context
-from nova import db
from nova import exception
from nova import flags
from nova import log as logging
--
cgit
From 0218a11bb1d5275d5b99c98aea1edba0f45f56e2 Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Wed, 23 Mar 2011 19:48:26 +0000
Subject: Forgot extraneous module import again
---
nova/api/openstack/views/servers.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 18d31a29d..68f712e56 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -20,7 +20,6 @@ import hashlib
from nova.compute import power_state
import nova.compute
import nova.context
-from nova import db
from nova.api.openstack import common
from nova.api.openstack.views import addresses as addresses_view
from nova.api.openstack.views import flavors as flavors_view
--
cgit
From a291e68fef876080d7984a1d7192e939808596bf Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Wed, 23 Mar 2011 14:55:33 -0500
Subject: Fixed some typos
---
nova/virt/xenapi/vmops.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index cb36730a0..0a516bd36 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -463,7 +463,7 @@ class VMOps(object):
except self.XenAPI.Failure, exc:
LOG.exception(exc)
- def _shutdown_rescue(self, vm_ref):
+ def _shutdown_rescue(self, rescue_vm_ref):
"""Shutdown a rescue instance"""
self._session.call_xenapi("Async.VM.hard_shutdown", rescue_vm_ref)
@@ -552,7 +552,7 @@ class VMOps(object):
LOG.debug(_("Instance %(instance_id)s VM destroyed") % locals())
- def _destroy_rescue(self, vm_ref):
+ def _destroy_rescue_instance(self, rescue_vm_ref):
"""Destroy a rescue instance"""
self._session.call_xenapi("Async.VM.destroy", rescue_vm_ref)
@@ -671,7 +671,7 @@ class VMOps(object):
self._destroy_rescue_vbds(rescue_vm_ref)
self._shutdown_rescue(rescue_vm_ref)
self._destroy_rescue_vdis(rescue_vm_ref)
- self._destroy_rescue(rescue_vm_ref)
+ self._destroy_rescue_instance(rescue_vm_ref)
self._release_bootlock(original_vm_ref)
self._start(instance, original_vm_ref)
@@ -709,7 +709,7 @@ class VMOps(object):
self._destroy_rescue_vbds(rescue_vm_ref)
self._shutdown_rescue(rescue_vm_ref)
self._destroy_rescue_vdis(rescue_vm_ref)
- self._destroy_rescue(rescue_vm_ref)
+ self._destroy_rescue_instance(rescue_vm_ref)
self._release_bootlock(original_vm_ref)
self._session.call_xenapi("VM.start", original_vm_ref, False,
False)
--
cgit
From 83e519b734078d8214fa0dc1d518607c7c0b244a Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Wed, 23 Mar 2011 15:21:18 -0500
Subject: Only run periodic task when rescue_timeout is greater than 0
---
nova/compute/manager.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 3834c33ab..9cb210c77 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -138,7 +138,8 @@ class ComputeManager(manager.Manager):
def periodic_tasks(self, context=None):
"""Tasks to be run at a periodic interval."""
super(ComputeManager, self).periodic_tasks(context)
- self.driver.poll_rescued_instances(FLAGS.rescue_timeout)
+ if FLAGS.rescue_timeout > 0:
+ self.driver.poll_rescued_instances(FLAGS.rescue_timeout)
def _update_state(self, context, instance_id):
"""Update the state of an instance from the driver info."""
--
cgit
From 0d677a9b63ed9b4612379494bf8a58af1c090331 Mon Sep 17 00:00:00 2001
From: Naveed Massjouni
Date: Wed, 23 Mar 2011 16:51:30 -0400
Subject: Should not call super __init__ twice in APIRouter
---
nova/api/openstack/__init__.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index e68110bc4..143b1d2b2 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -127,8 +127,6 @@ class APIRouter(wsgi.Router):
_limits = limits.LimitsController()
mapper.resource("limit", "limits", controller=_limits)
- super(APIRouter, self).__init__(mapper)
-
class APIRouterV10(APIRouter):
"""Define routes specific to OpenStack API V1.0."""
--
cgit
From 98b4f0924257dcfa12e4881950472e983f08ef1d Mon Sep 17 00:00:00 2001
From: "matt.dietz@rackspace.com" <>
Date: Wed, 23 Mar 2011 21:04:42 +0000
Subject: merge prop fixes
---
nova/compute/api.py | 10 +++++++---
nova/tests/test_compute.py | 14 +++++++++++++-
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index c2738f6f5..01eead4ac 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -260,7 +260,7 @@ class API(base.Base):
db.migration_get_by_instance_and_status(context, instance_id,
'finished')
return True
- except Exception, e:
+ except exception.NotFound:
return False
def ensure_default_security_group(self, context):
@@ -512,10 +512,14 @@ class API(base.Base):
raise exception.ApiError(_("Requested flavor %(flavor_id)d "
"does not exist") % locals())
- if current_instance_type['memory_mb'] >= \
- new_instance_type['memory_mb']:
+ current_memory_mb = current_instance_type['memory_mb']
+ new_memory_mb = new_instance_type['memory_mb']
+ if current_memory_mb > new_memory_mb:
raise exception.ApiError(_("Invalid flavor: cannot downsize"
"instances"))
+ if current_memory_mb == new_memory_mb:
+ raise exception.ApiError(_("Invalid flavor: cannot use"
+ "the same flavor. "))
self._cast_scheduler_message(context,
{"method": "prep_resize",
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index 444be5dd8..44d04a12f 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -336,7 +336,7 @@ class ComputeTestCase(test.TestCase):
self.compute.terminate_instance(context, instance_id)
def test_resize_down_fails(self):
- """Ensure invalid flavors raise"""
+ """Ensure resizing down raises and fails"""
context = self.context.elevated()
instance_id = self._create_instance()
@@ -349,6 +349,18 @@ class ComputeTestCase(test.TestCase):
self.compute.terminate_instance(context, instance_id)
+ def test_resize_same_size_fails(self):
+ """Ensure invalid flavors raise"""
+ context = self.context.elevated()
+ instance_id = self._create_instance()
+
+ self.compute.run_instance(self.context, instance_id)
+
+ self.assertRaises(exception.ApiError, self.compute_api.resize,
+ context, instance_id, 1)
+
+ self.compute.terminate_instance(context, instance_id)
+
def test_get_by_flavor_id(self):
type = instance_types.get_by_flavor_id(1)
self.assertEqual(type, 'm1.tiny')
--
cgit
From b3a8c70304672abe9b461c6cfeed3e8b517ca0b6 Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Wed, 23 Mar 2011 16:56:54 -0500
Subject: Added docstring
---
nova/utils.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/nova/utils.py b/nova/utils.py
index 38cdb8021..bf1aa4a91 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -335,6 +335,7 @@ utcnow.override_time = None
def is_then_greater(then, seconds):
+ """Return True of 'then' is greater than 'seconds'"""
if utcnow() - then > datetime.timedelta(seconds=seconds):
return True
else:
--
cgit
From a12b6f0a0808fba5541723a537118447b55b69ad Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Wed, 23 Mar 2011 17:15:41 -0500
Subject: Better method name
---
nova/utils.py | 6 +++---
nova/virt/xenapi/vmops.py | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/nova/utils.py b/nova/utils.py
index bf1aa4a91..04b6c9778 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -334,9 +334,9 @@ def utcnow():
utcnow.override_time = None
-def is_then_greater(then, seconds):
- """Return True of 'then' is greater than 'seconds'"""
- if utcnow() - then > datetime.timedelta(seconds=seconds):
+def is_older_than(before, seconds):
+ """Return True if before is older than 'seconds'"""
+ if utcnow() - before > datetime.timedelta(seconds=seconds):
return True
else:
return False
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 0a516bd36..3f1eceddc 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -682,7 +682,7 @@ class VMOps(object):
"""
last_ran = self.poll_rescue_last_ran
if last_ran:
- if not utils.is_then_greater(last_ran, timeout * 60 * 60):
+ if not utils.is_older_than(last_ran, timeout * 60 * 60):
# Do not run. Let's bail.
return
else:
--
cgit
From e19b12f668fb6cd693df6834f8895fb5487953d7 Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Wed, 23 Mar 2011 18:34:47 -0500
Subject: Review feedback
---
nova/compute/manager.py | 2 +-
nova/virt/xenapi/vmops.py | 30 +++++++++++++++---------------
2 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 9cb210c77..ce1ae87e3 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -68,7 +68,7 @@ flags.DEFINE_integer('live_migration_retry_count', 30,
"Retry count needed in live_migration."
" sleep 1 sec for each count")
flags.DEFINE_integer("rescue_timeout", 0,
- "Automatically unrescue an instance after N hours."
+ "Automatically unrescue an instance after N seconds."
" Set to 0 to disable.")
LOG = logging.getLogger('nova.compute.manager')
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 3f1eceddc..1f2e10aa6 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -497,8 +497,8 @@ class VMOps(object):
"""Destroys all VBDs tied to a rescue VM"""
vbd_refs = self._session.get_xenapi().VM.get_VBDs(rescue_vm_ref)
for vbd_ref in vbd_refs:
- _vbd_ref = self._session.get_xenapi().VBD.get_record(vbd_ref)
- if _vbd_ref["userdevice"] == "1":
+ vbd_rec = self._session.get_xenapi().VBD.get_record(vbd_ref)
+ if vbd_rec["userdevice"] == "1": # primary VBD is always 1
VMHelper.unplug_vbd(self._session, vbd_ref)
VMHelper.destroy_vbd(self._session, vbd_ref)
@@ -554,6 +554,10 @@ class VMOps(object):
def _destroy_rescue_instance(self, rescue_vm_ref):
"""Destroy a rescue instance"""
+ self._destroy_rescue_vbds(rescue_vm_ref)
+ self._shutdown_rescue(rescue_vm_ref)
+ self._destroy_rescue_vdis(rescue_vm_ref)
+
self._session.call_xenapi("Async.VM.destroy", rescue_vm_ref)
def destroy(self, instance):
@@ -668,9 +672,6 @@ class VMOps(object):
original_vm_ref = self._get_vm_opaque_ref(instance)
instance._rescue = False
- self._destroy_rescue_vbds(rescue_vm_ref)
- self._shutdown_rescue(rescue_vm_ref)
- self._destroy_rescue_vdis(rescue_vm_ref)
self._destroy_rescue_instance(rescue_vm_ref)
self._release_bootlock(original_vm_ref)
self._start(instance, original_vm_ref)
@@ -682,7 +683,7 @@ class VMOps(object):
"""
last_ran = self.poll_rescue_last_ran
if last_ran:
- if not utils.is_older_than(last_ran, timeout * 60 * 60):
+ if not utils.is_older_than(last_ran, timeout):
# Do not run. Let's bail.
return
else:
@@ -693,23 +694,22 @@ class VMOps(object):
self.poll_rescue_last_ran = utils.utcnow()
return
- vms = []
+ rescue_vms = []
for instance in self.list_instances():
if instance.endswith("-rescue"):
- vms.append(dict(name=instance,
- vm_ref=VMHelper.lookup(self._session,
- instance)))
+ rescue_vms.append(dict(name=instance,
+ vm_ref=VMHelper.lookup(self._session,
+ instance)))
- for vm in vms:
+ for vm in rescue_vms:
rescue_name = vm["name"]
rescue_vm_ref = vm["vm_ref"]
+
+ self._destroy_rescue_instance(rescue_vm_ref)
+
original_name = vm["name"].split("-rescue", 1)[0]
original_vm_ref = VMHelper.lookup(self._session, original_name)
- self._destroy_rescue_vbds(rescue_vm_ref)
- self._shutdown_rescue(rescue_vm_ref)
- self._destroy_rescue_vdis(rescue_vm_ref)
- self._destroy_rescue_instance(rescue_vm_ref)
self._release_bootlock(original_vm_ref)
self._session.call_xenapi("VM.start", original_vm_ref, False,
False)
--
cgit
From 7a93455f41e5198fdce8aa1b3091efd956e1c186 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 23 Mar 2011 16:49:50 -0700
Subject: Doh! Missed two places which were importing the old driver location
---
nova/virt/connection.py | 2 +-
nova/virt/xenapi/vmops.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/virt/connection.py b/nova/virt/connection.py
index 4ba31c7a7..af7001715 100644
--- a/nova/virt/connection.py
+++ b/nova/virt/connection.py
@@ -24,7 +24,7 @@ import sys
from nova import flags
from nova import log as logging
from nova import utils
-from nova.compute import driver
+from nova.virt import driver
from nova.virt import fake
from nova.virt import libvirt_conn
from nova.virt import xenapi_conn
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 2a9694f45..3fd98be67 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -35,8 +35,8 @@ from nova import exception
from nova import utils
from nova.auth.manager import AuthManager
-from nova.compute import driver
from nova.compute import power_state
+from nova.virt import driver
from nova.virt.xenapi.network_utils import NetworkHelper
from nova.virt.xenapi.vm_utils import VMHelper
from nova.virt.xenapi.vm_utils import ImageType
--
cgit
From 3c295817f91eb7c76a64d157ff4a938c85075a36 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 23 Mar 2011 18:50:30 -0700
Subject: pep8 fixes, backported some important fixes that didn't make it over
from my testing system :-(
---
nova/compute/manager.py | 2 +-
nova/compute/power_state.py | 2 +-
nova/virt/driver.py | 9 ++++-----
nova/virt/libvirt_conn.py | 2 +-
4 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index d85ead88b..b67b27dd0 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1001,7 +1001,7 @@ class ComputeManager(manager.Manager):
vm_instances = dict((vm.name, vm) for vm in vm_instances)
# Keep a list of VMs not in the DB, cross them off as we find them
- vms_not_found_in_db = [vm.name for vm in vm_instances]
+ vms_not_found_in_db = list(vm_instances.keys())
db_instances = self.db.instance_get_all_by_host(context, self.host)
diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py
index ed50e492e..ef013b2ef 100644
--- a/nova/compute/power_state.py
+++ b/nova/compute/power_state.py
@@ -51,4 +51,4 @@ def name(code):
def valid_states():
- return _STATE_MAP.values()
+ return _STATE_MAP.keys()
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index d01a91b93..e82f49ebe 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -28,13 +28,13 @@ from nova.compute import power_state
class InstanceInfo(object):
def __init__(self, name, state):
self.name = name
- assert state in power_state.valid_states()
+ assert state in power_state.valid_states(), "Bad state: %s" % state
self.state = state
class ComputeDriver(object):
"""Base class for compute drivers.
-
+
Lots of documentation is currently on fake.py.
"""
@@ -44,7 +44,7 @@ class ComputeDriver(object):
def get_info(self, instance_name):
"""Get the current status of an instance, by name (not ID!)
-
+
Returns a dict containing:
:state: the running state, one of the power_state codes
:max_mem: (int) the maximum memory in KBytes allowed
@@ -78,7 +78,7 @@ class ComputeDriver(object):
def get_console_pool_info(self, console_type):
"""???
-
+
Returns a dict containing:
:address: ???
:username: ???
@@ -228,4 +228,3 @@ class ComputeDriver(object):
def inject_network_info(self, instance):
"""inject network info for specified instance"""
raise NotImplementedError()
-
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index e57859f9d..ddc525e06 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -255,7 +255,7 @@ class LibvirtConnection(driver.ComputeDriver):
def list_instances_detail(self):
infos = []
for domain_id in self._conn.listDomainsID():
- domain = self._conn.lookupById(domain_id)
+ domain = self._conn.lookupByID(domain_id)
info = self._map_to_instance_info(domain)
infos.append(info)
return infos
--
cgit
From 31940b550e49c23ba29c71a0e0593a6d14331516 Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 23 Mar 2011 19:02:20 -0700
Subject: Added revert_resize to base class
---
nova/virt/driver.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index e82f49ebe..4c77048be 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -120,6 +120,10 @@ class ComputeDriver(object):
def finish_resize(self, instance, disk_info):
"""Completes a resize, turning on the migrated instance"""
raise NotImplementedError()
+
+ def revert_resize(self, instance):
+ """Reverts a resize, powering back on the instance"""
+ raise NotImplementedError()
def pause(self, instance, callback):
"""Pause VM instance"""
--
cgit
From 3cde42aaac50e32f2c8fcd4493c40a2eaf1a0d4d Mon Sep 17 00:00:00 2001
From: Justin Santa Barbara
Date: Wed, 23 Mar 2011 19:15:41 -0700
Subject: pep8 fix
---
nova/virt/driver.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index 4c77048be..0e3a4aa3b 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -120,7 +120,7 @@ class ComputeDriver(object):
def finish_resize(self, instance, disk_info):
"""Completes a resize, turning on the migrated instance"""
raise NotImplementedError()
-
+
def revert_resize(self, instance):
"""Reverts a resize, powering back on the instance"""
raise NotImplementedError()
--
cgit
From 10e61af8a23c126c15fcfcf25156d32facf19ec2 Mon Sep 17 00:00:00 2001
From: Josh Kearney
Date: Wed, 23 Mar 2011 22:55:04 -0500
Subject: Added hyperv stub
---
nova/virt/hyperv.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py
index 29d18dac5..75fed6d4f 100644
--- a/nova/virt/hyperv.py
+++ b/nova/virt/hyperv.py
@@ -467,3 +467,6 @@ class HyperVConnection(object):
if vm is None:
raise exception.NotFound('Cannot detach volume from missing %s '
% instance_name)
+
+ def poll_rescued_instances(self, timeout):
+ pass
--
cgit
From f52a2a8a440b303e5289815ab4f6c2d24bfdc59f Mon Sep 17 00:00:00 2001
From: Naveed Massjouni
Date: Thu, 24 Mar 2011 01:41:38 -0400
Subject: Fixed the docstring for common.get_id_from_href
---
nova/api/openstack/common.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index 21ceec45e..bff050347 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -79,10 +79,10 @@ def get_image_id_from_image_hash(image_service, context, image_hash):
def get_id_from_href(href):
- """Return the id portion of a url.
+ """Return the id portion of a url as an int.
Given: http://www.foo.com/bar/123?q=4
- Returns: 4
+ Returns: 123
"""
try:
--
cgit