summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorMichael Gundlach <michael.gundlach@rackspace.com>2010-09-16 11:33:42 -0400
committerMichael Gundlach <michael.gundlach@rackspace.com>2010-09-16 11:33:42 -0400
commita458a5a6987f151403aa8d4fbc9440396712e3d7 (patch)
treed2823ebaa3448e6f01092029b1c0f8f9edd956e2 /nova/api
parent29bf1a618658b20797bf208385bea9b92419e967 (diff)
parente21c310ced6992cf2eb33b372cd4e5e69a79d140 (diff)
downloadnova-a458a5a6987f151403aa8d4fbc9440396712e3d7.tar.gz
nova-a458a5a6987f151403aa8d4fbc9440396712e3d7.tar.xz
nova-a458a5a6987f151403aa8d4fbc9440396712e3d7.zip
Merge from trunk (pulling in orm_deux)
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/ec2/admin.py11
-rw-r--r--nova/api/ec2/cloud.py588
-rw-r--r--nova/api/ec2/images.py12
-rw-r--r--nova/api/rackspace/servers.py29
4 files changed, 304 insertions, 336 deletions
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index f0c643bbd..36feae451 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -22,8 +22,9 @@ Admin API controller, exposed through http via the api worker.
import base64
+from nova import db
+from nova import exception
from nova.auth import manager
-from nova.compute import model
def user_dict(user, base64_file=None):
@@ -153,7 +154,7 @@ class AdminController(object):
result = {
'members': [{'member': m} for m in project.member_ids]}
return result
-
+
def modify_project_member(self, context, user, project, operation, **kwargs):
"""Add or remove a user from a project."""
if operation =='add':
@@ -164,6 +165,8 @@ class AdminController(object):
raise exception.ApiError('operation must be add or remove')
return True
+ # FIXME(vish): these host commands don't work yet, perhaps some of the
+ # required data can be retrieved from service objects?
def describe_hosts(self, _context, **_kwargs):
"""Returns status info for all nodes. Includes:
* Disk Space
@@ -173,8 +176,8 @@ class AdminController(object):
* DHCP servers running
* Iptables / bridges
"""
- return {'hostSet': [host_dict(h) for h in model.Host.all()]}
+ return {'hostSet': [host_dict(h) for h in db.host_get_all()]}
def describe_host(self, _context, name, **_kwargs):
"""Returns status info for single node."""
- return host_dict(model.Host.lookup(name))
+ return host_dict(db.host_get(name))
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index e1e04ca90..7a9b5f5cf 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -27,21 +27,18 @@ import logging
import os
import time
-from nova import datastore
+from nova import db
from nova import exception
from nova import flags
from nova import rpc
from nova import utils
from nova.auth import manager
-from nova.compute import model
from nova.compute.instance_types import INSTANCE_TYPES
from nova.api.ec2 import images
-from nova.network import service as network_service
-from nova.network import model as network_model
-from nova.volume import service
FLAGS = flags.FLAGS
+flags.DECLARE('storage_availability_zone', 'nova.volume.manager')
def _gen_key(user_id, key_name):
@@ -57,26 +54,16 @@ class CloudController(object):
sent to the other nodes.
"""
def __init__(self):
- self.instdir = model.InstanceDirectory()
+ self.network_manager = utils.import_object(FLAGS.network_manager)
self.setup()
- @property
- def instances(self):
- """ All instances in the system, as dicts """
- return self.instdir.all
-
- @property
- def volumes(self):
- """ returns a list of all volumes """
- for volume_id in datastore.Redis.instance().smembers("volumes"):
- volume = service.get_volume(volume_id)
- yield volume
-
def __str__(self):
return 'CloudController'
def setup(self):
""" Ensure the keychains and folders exist. """
+ # FIXME(ja): this should be moved to a nova-manage command,
+ # if not setup throw exceptions instead of running
# Create keys folder, if it doesn't exist
if not os.path.exists(FLAGS.keys_path):
os.makedirs(FLAGS.keys_path)
@@ -85,18 +72,15 @@ class CloudController(object):
if not os.path.exists(root_ca_path):
start = os.getcwd()
os.chdir(FLAGS.ca_path)
+ # TODO(vish): Do this with M2Crypto instead
utils.runthis("Generating root CA: %s", "sh genrootca.sh")
os.chdir(start)
- # TODO: Do this with M2Crypto instead
-
- def get_instance_by_ip(self, ip):
- return self.instdir.by_ip(ip)
def _get_mpi_data(self, project_id):
result = {}
- for instance in self.instdir.all:
- if instance['project_id'] == project_id:
- line = '%s slots=%d' % (instance['private_dns_name'],
+ for instance in db.instance_get_by_project(None, project_id):
+ if instance['fixed_ip']:
+ line = '%s slots=%d' % (instance['fixed_ip']['str_id'],
INSTANCE_TYPES[instance['instance_type']]['vcpus'])
if instance['key_name'] in result:
result[instance['key_name']].append(line)
@@ -104,33 +88,30 @@ class CloudController(object):
result[instance['key_name']] = [line]
return result
- def get_metadata(self, ipaddress):
- i = self.get_instance_by_ip(ipaddress)
- if i is None:
+ def get_metadata(self, address):
+ instance_ref = db.fixed_ip_get_instance(None, address)
+ if instance_ref is None:
return None
- mpi = self._get_mpi_data(i['project_id'])
- if i['key_name']:
+ mpi = self._get_mpi_data(instance_ref['project_id'])
+ if instance_ref['key_name']:
keys = {
'0': {
- '_name': i['key_name'],
- 'openssh-key': i['key_data']
+ '_name': instance_ref['key_name'],
+ 'openssh-key': instance_ref['key_data']
}
}
else:
keys = ''
-
- address_record = network_model.FixedIp(i['private_dns_name'])
- if address_record:
- hostname = address_record['hostname']
- else:
- hostname = 'ip-%s' % i['private_dns_name'].replace('.', '-')
+ hostname = instance_ref['hostname']
+ floating_ip = db.instance_get_floating_address(None,
+ instance_ref['id'])
data = {
- 'user-data': base64.b64decode(i['user_data']),
+ 'user-data': base64.b64decode(instance_ref['user_data']),
'meta-data': {
- 'ami-id': i['image_id'],
- 'ami-launch-index': i['ami_launch_index'],
- 'ami-manifest-path': 'FIXME', # image property
- 'block-device-mapping': { # TODO: replace with real data
+ 'ami-id': instance_ref['image_id'],
+ 'ami-launch-index': instance_ref['launch_index'],
+ 'ami-manifest-path': 'FIXME',
+ 'block-device-mapping': { # TODO(vish): replace with real data
'ami': 'sda1',
'ephemeral0': 'sda2',
'root': '/dev/sda1',
@@ -138,27 +119,27 @@ class CloudController(object):
},
'hostname': hostname,
'instance-action': 'none',
- 'instance-id': i['instance_id'],
- 'instance-type': i.get('instance_type', ''),
+ 'instance-id': instance_ref['str_id'],
+ 'instance-type': instance_ref['instance_type'],
'local-hostname': hostname,
- 'local-ipv4': i['private_dns_name'], # TODO: switch to IP
- 'kernel-id': i.get('kernel_id', ''),
+ 'local-ipv4': address,
+ 'kernel-id': instance_ref['kernel_id'],
'placement': {
- 'availaibility-zone': i.get('availability_zone', 'nova'),
+ 'availability-zone': 'nova' # TODO(vish): real zone
},
'public-hostname': hostname,
- 'public-ipv4': i.get('dns_name', ''), # TODO: switch to IP
+ 'public-ipv4': floating_ip or '',
'public-keys': keys,
- 'ramdisk-id': i.get('ramdisk_id', ''),
- 'reservation-id': i['reservation_id'],
- 'security-groups': i.get('groups', ''),
+ 'ramdisk-id': instance_ref['ramdisk_id'],
+ 'reservation-id': instance_ref['reservation_id'],
+ 'security-groups': '',
'mpi': mpi
}
}
- if False: # TODO: store ancestor ids
+ if False: # TODO(vish): store ancestor ids
data['ancestor-ami-ids'] = []
- if i.get('product_codes', None):
- data['product-codes'] = i['product_codes']
+ if False: # TODO(vish): store product codes
+ data['product-codes'] = []
return data
def describe_availability_zones(self, context, **kwargs):
@@ -227,137 +208,110 @@ class CloudController(object):
def get_console_output(self, context, instance_id, **kwargs):
# instance_id is passed in as a list of instances
- instance = self._get_instance(context, instance_id[0])
- return rpc.call('%s.%s' % (FLAGS.compute_topic, instance['node_name']),
- {"method": "get_console_output",
- "args": {"instance_id": instance_id[0]}})
-
- def _get_user_id(self, context):
- if context and context.user:
- return context.user.id
- else:
- return None
+ instance_ref = db.instance_get_by_str(context, instance_id[0])
+ return rpc.call('%s.%s' % (FLAGS.compute_topic,
+ instance_ref['host']),
+ {"method": "get_console_output",
+ "args": {"context": None,
+ "instance_id": instance_ref['id']}})
def describe_volumes(self, context, **kwargs):
- volumes = []
- for volume in self.volumes:
- if context.user.is_admin() or volume['project_id'] == context.project.id:
- v = self.format_volume(context, volume)
- volumes.append(v)
+ if context.user.is_admin():
+ volumes = db.volume_get_all(context)
+ else:
+ volumes = db.volume_get_by_project(context, context.project.id)
+
+ volumes = [self._format_volume(context, v) for v in volumes]
+
return {'volumeSet': volumes}
- def format_volume(self, context, volume):
+ def _format_volume(self, context, volume):
v = {}
- v['volumeId'] = volume['volume_id']
+ v['volumeId'] = volume['str_id']
v['status'] = volume['status']
v['size'] = volume['size']
v['availabilityZone'] = volume['availability_zone']
- v['createTime'] = volume['create_time']
+ v['createTime'] = volume['created_at']
if context.user.is_admin():
v['status'] = '%s (%s, %s, %s, %s)' % (
- volume.get('status', None),
- volume.get('user_id', None),
- volume.get('node_name', None),
- volume.get('instance_id', ''),
- volume.get('mountpoint', ''))
+ volume['status'],
+ volume['user_id'],
+ volume['host'],
+ volume['instance_id'],
+ volume['mountpoint'])
if volume['attach_status'] == 'attached':
v['attachmentSet'] = [{'attachTime': volume['attach_time'],
- 'deleteOnTermination': volume['delete_on_termination'],
+ 'deleteOnTermination': False,
'device': volume['mountpoint'],
'instanceId': volume['instance_id'],
'status': 'attached',
- 'volume_id': volume['volume_id']}]
+ 'volume_id': volume['str_id']}]
else:
v['attachmentSet'] = [{}]
return v
def create_volume(self, context, size, **kwargs):
- # TODO(vish): refactor this to create the volume object here and tell service to create it
- result = rpc.call(FLAGS.volume_topic,
- {"method": "create_volume",
- "args": {"size": size,
- "user_id": context.user.id,
- "project_id": context.project.id}})
- # NOTE(vish): rpc returned value is in the result key in the dictionary
- volume = self._get_volume(context, result)
- return {'volumeSet': [self.format_volume(context, volume)]}
-
- def _get_address(self, context, public_ip):
- # FIXME(vish) this should move into network.py
- address = network_model.ElasticIp.lookup(public_ip)
- if address and (context.user.is_admin() or address['project_id'] == context.project.id):
- return address
- raise exception.NotFound("Address at ip %s not found" % public_ip)
-
- def _get_image(self, context, image_id):
- """passes in context because
- objectstore does its own authorization"""
- result = images.list(context, [image_id])
- if not result:
- raise exception.NotFound('Image %s could not be found' % image_id)
- image = result[0]
- return image
-
- def _get_instance(self, context, instance_id):
- for instance in self.instdir.all:
- if instance['instance_id'] == instance_id:
- if context.user.is_admin() or instance['project_id'] == context.project.id:
- return instance
- raise exception.NotFound('Instance %s could not be found' % instance_id)
-
- def _get_volume(self, context, volume_id):
- volume = service.get_volume(volume_id)
- if context.user.is_admin() or volume['project_id'] == context.project.id:
- return volume
- raise exception.NotFound('Volume %s could not be found' % volume_id)
+ vol = {}
+ vol['size'] = size
+ vol['user_id'] = context.user.id
+ vol['project_id'] = context.project.id
+ vol['availability_zone'] = FLAGS.storage_availability_zone
+ vol['status'] = "creating"
+ vol['attach_status'] = "detached"
+ volume_ref = db.volume_create(context, vol)
+
+ rpc.cast(FLAGS.volume_topic, {"method": "create_volume",
+ "args": {"context": None,
+ "volume_id": volume_ref['id']}})
+
+ return {'volumeSet': [self._format_volume(context, volume_ref)]}
+
def attach_volume(self, context, volume_id, instance_id, device, **kwargs):
- volume = self._get_volume(context, volume_id)
- if volume['status'] == "attached":
+ volume_ref = db.volume_get_by_str(context, volume_id)
+ # TODO(vish): abstract status checking?
+ if volume_ref['attach_status'] == "attached":
raise exception.ApiError("Volume is already attached")
- # TODO(vish): looping through all volumes is slow. We should probably maintain an index
- for vol in self.volumes:
- if vol['instance_id'] == instance_id and vol['mountpoint'] == device:
- raise exception.ApiError("Volume %s is already attached to %s" % (vol['volume_id'], vol['mountpoint']))
- volume.start_attach(instance_id, device)
- instance = self._get_instance(context, instance_id)
- compute_node = instance['node_name']
- rpc.cast('%s.%s' % (FLAGS.compute_topic, compute_node),
+ instance_ref = db.instance_get_by_str(context, instance_id)
+ host = instance_ref['host']
+ rpc.cast(db.queue_get_for(context, FLAGS.compute_topic, host),
{"method": "attach_volume",
- "args": {"volume_id": volume_id,
- "instance_id": instance_id,
- "mountpoint": device}})
- return {'attachTime': volume['attach_time'],
- 'device': volume['mountpoint'],
- 'instanceId': instance_id,
+ "args": {"context": None,
+ "volume_id": volume_ref['id'],
+ "instance_id": instance_ref['id'],
+ "mountpoint": device}})
+ return {'attachTime': volume_ref['attach_time'],
+ 'device': volume_ref['mountpoint'],
+ 'instanceId': instance_ref['id'],
'requestId': context.request_id,
- 'status': volume['attach_status'],
- 'volumeId': volume_id}
+ 'status': volume_ref['attach_status'],
+ 'volumeId': volume_ref['id']}
def detach_volume(self, context, volume_id, **kwargs):
- volume = self._get_volume(context, volume_id)
- instance_id = volume.get('instance_id', None)
- if not instance_id:
+ volume_ref = db.volume_get_by_str(context, volume_id)
+ instance_ref = db.volume_get_instance(context, volume_ref['id'])
+ if not instance_ref:
raise exception.Error("Volume isn't attached to anything!")
- if volume['status'] == "available":
+ # TODO(vish): abstract status checking?
+ if volume_ref['status'] == "available":
raise exception.Error("Volume is already detached")
try:
- volume.start_detach()
- instance = self._get_instance(context, instance_id)
- rpc.cast('%s.%s' % (FLAGS.compute_topic, instance['node_name']),
+ host = instance_ref['host']
+ rpc.cast(db.queue_get_for(context, FLAGS.compute_topic, host),
{"method": "detach_volume",
- "args": {"instance_id": instance_id,
- "volume_id": volume_id}})
+ "args": {"context": None,
+ "instance_id": instance_ref['id'],
+ "volume_id": volume_ref['id']}})
except exception.NotFound:
# If the instance doesn't exist anymore,
# then we need to call detach blind
- volume.finish_detach()
- return {'attachTime': volume['attach_time'],
- 'device': volume['mountpoint'],
- 'instanceId': instance_id,
+ db.volume_detached(context)
+ return {'attachTime': volume_ref['attach_time'],
+ 'device': volume_ref['mountpoint'],
+ 'instanceId': instance_ref['str_id'],
'requestId': context.request_id,
- 'status': volume['attach_status'],
- 'volumeId': volume_id}
+ 'status': volume_ref['attach_status'],
+ 'volumeId': volume_ref['id']}
def _convert_to_set(self, lst, label):
if lst == None or lst == []:
@@ -377,52 +331,55 @@ class CloudController(object):
assert len(i) == 1
return i[0]
- def _format_instances(self, context, reservation_id = None):
+ def _format_instances(self, context, reservation_id=None):
reservations = {}
- if context.user.is_admin():
- instgenerator = self.instdir.all
+ if reservation_id:
+ instances = db.instance_get_by_reservation(context,
+ reservation_id)
else:
- instgenerator = self.instdir.by_project(context.project.id)
- for instance in instgenerator:
- res_id = instance.get('reservation_id', 'Unknown')
- if reservation_id != None and reservation_id != res_id:
- continue
+ if not context.user.is_admin():
+ instances = db.instance_get_all(context)
+ else:
+ instances = db.instance_get_by_project(context,
+ context.project.id)
+ for instance in instances:
if not context.user.is_admin():
if instance['image_id'] == FLAGS.vpn_image_id:
continue
i = {}
- i['instance_id'] = instance.get('instance_id', None)
- i['image_id'] = instance.get('image_id', None)
- i['instance_state'] = {
- 'code': instance.get('state', 0),
- 'name': instance.get('state_description', 'pending')
+ i['instanceId'] = instance['str_id']
+ i['imageId'] = instance['image_id']
+ i['instanceState'] = {
+ 'code': instance['state'],
+ 'name': instance['state_description']
}
- i['public_dns_name'] = network_model.get_public_ip_for_instance(
- i['instance_id'])
- i['private_dns_name'] = instance.get('private_dns_name', None)
- if not i['public_dns_name']:
- i['public_dns_name'] = i['private_dns_name']
- i['dns_name'] = instance.get('dns_name', None)
- i['key_name'] = instance.get('key_name', None)
+ fixed_addr = None
+ floating_addr = None
+ if instance['fixed_ip']:
+ fixed_addr = instance['fixed_ip']['str_id']
+ if instance['fixed_ip']['floating_ips']:
+ fixed = instance['fixed_ip']
+ floating_addr = fixed['floating_ips'][0]['str_id']
+ i['privateDnsName'] = fixed_addr
+ i['publicDnsName'] = floating_addr
+ i['dnsName'] = i['publicDnsName'] or i['privateDnsName']
+ i['keyName'] = instance['key_name']
if context.user.is_admin():
- i['key_name'] = '%s (%s, %s)' % (i['key_name'],
- instance.get('project_id', None),
- instance.get('node_name', ''))
- i['product_codes_set'] = self._convert_to_set(
- instance.get('product_codes', None), 'product_code')
- i['instance_type'] = instance.get('instance_type', None)
- i['launch_time'] = instance.get('launch_time', None)
- i['ami_launch_index'] = instance.get('ami_launch_index',
- None)
- if not reservations.has_key(res_id):
+ i['keyName'] = '%s (%s, %s)' % (i['keyName'],
+ instance['project_id'],
+ instance['host'])
+ i['productCodesSet'] = self._convert_to_set([], 'product_codes')
+ i['instanceType'] = instance['instance_type']
+ i['launchTime'] = instance['created_at']
+ i['amiLaunchIndex'] = instance['launch_index']
+ if not reservations.has_key(instance['reservation_id']):
r = {}
- r['reservation_id'] = res_id
- r['owner_id'] = instance.get('project_id', None)
- r['group_set'] = self._convert_to_set(
- instance.get('groups', None), 'group_id')
- r['instances_set'] = []
- reservations[res_id] = r
- reservations[res_id]['instances_set'].append(i)
+ r['reservationId'] = instance['reservation_id']
+ r['ownerId'] = instance['project_id']
+ r['groupSet'] = self._convert_to_set([], 'groups')
+ r['instancesSet'] = []
+ reservations[instance['reservation_id']] = r
+ reservations[instance['reservation_id']]['instancesSet'].append(i)
return list(reservations.values())
@@ -431,76 +388,85 @@ class CloudController(object):
def format_addresses(self, context):
addresses = []
- for address in network_model.ElasticIp.all():
- # TODO(vish): implement a by_project iterator for addresses
- if (context.user.is_admin() or
- address['project_id'] == context.project.id):
- address_rv = {
- 'public_ip': address['address'],
- 'instance_id': address.get('instance_id', 'free')
- }
- if context.user.is_admin():
- address_rv['instance_id'] = "%s (%s, %s)" % (
- address['instance_id'],
- address['user_id'],
- address['project_id'],
- )
+ if context.user.is_admin():
+ iterator = db.floating_ip_get_all(context)
+ else:
+ iterator = db.floating_ip_get_by_project(context,
+ context.project.id)
+ for floating_ip_ref in iterator:
+ address = floating_ip_ref['str_id']
+ instance_id = None
+ if (floating_ip_ref['fixed_ip']
+ and floating_ip_ref['fixed_ip']['instance']):
+ instance_id = floating_ip_ref['fixed_ip']['instance']['str_id']
+ address_rv = {'public_ip': address,
+ 'instance_id': instance_id}
+ if context.user.is_admin():
+ details = "%s (%s)" % (address_rv['instance_id'],
+ floating_ip_ref['project_id'])
+ address_rv['instance_id'] = details
addresses.append(address_rv)
return {'addressesSet': addresses}
def allocate_address(self, context, **kwargs):
network_topic = self._get_network_topic(context)
public_ip = rpc.call(network_topic,
- {"method": "allocate_elastic_ip",
- "args": {"user_id": context.user.id,
+ {"method": "allocate_floating_ip",
+ "args": {"context": None,
"project_id": context.project.id}})
return {'addressSet': [{'publicIp': public_ip}]}
def release_address(self, context, public_ip, **kwargs):
# NOTE(vish): Should we make sure this works?
+ floating_ip_ref = db.floating_ip_get_by_address(context, public_ip)
network_topic = self._get_network_topic(context)
rpc.cast(network_topic,
- {"method": "deallocate_elastic_ip",
- "args": {"elastic_ip": public_ip}})
+ {"method": "deallocate_floating_ip",
+ "args": {"context": None,
+ "floating_address": floating_ip_ref['str_id']}})
return {'releaseResponse': ["Address released."]}
def associate_address(self, context, instance_id, public_ip, **kwargs):
- instance = self._get_instance(context, instance_id)
- address = self._get_address(context, public_ip)
+ instance_ref = db.instance_get_by_str(context, instance_id)
+ fixed_ip_ref = db.fixed_ip_get_by_instance(context, instance_ref['id'])
+ floating_ip_ref = db.floating_ip_get_by_address(context, public_ip)
network_topic = self._get_network_topic(context)
rpc.cast(network_topic,
- {"method": "associate_elastic_ip",
- "args": {"elastic_ip": address['address'],
- "fixed_ip": instance['private_dns_name'],
- "instance_id": instance['instance_id']}})
+ {"method": "associate_floating_ip",
+ "args": {"context": None,
+ "floating_address": floating_ip_ref['str_id'],
+ "fixed_address": fixed_ip_ref['str_id']}})
return {'associateResponse': ["Address associated."]}
def disassociate_address(self, context, public_ip, **kwargs):
- address = self._get_address(context, public_ip)
+ floating_ip_ref = db.floating_ip_get_by_address(context, public_ip)
network_topic = self._get_network_topic(context)
rpc.cast(network_topic,
- {"method": "disassociate_elastic_ip",
- "args": {"elastic_ip": address['address']}})
+ {"method": "disassociate_floating_ip",
+ "args": {"context": None,
+ "floating_address": floating_ip_ref['str_id']}})
return {'disassociateResponse': ["Address disassociated."]}
def _get_network_topic(self, context):
"""Retrieves the network host for a project"""
- host = network_service.get_host_for_project(context.project.id)
+ network_ref = db.project_get_network(context, context.project.id)
+ host = network_ref['host']
if not host:
host = rpc.call(FLAGS.network_topic,
- {"method": "set_network_host",
- "args": {"user_id": context.user.id,
- "project_id": context.project.id}})
- return '%s.%s' %(FLAGS.network_topic, host)
+ {"method": "set_network_host",
+ "args": {"context": None,
+ "project_id": context.project.id}})
+ return db.queue_get_for(context, FLAGS.network_topic, host)
def run_instances(self, context, **kwargs):
# make sure user can access the image
# vpn image is private so it doesn't show up on lists
- if kwargs['image_id'] != FLAGS.vpn_image_id:
- image = self._get_image(context, kwargs['image_id'])
+ vpn = kwargs['image_id'] == FLAGS.vpn_image_id
- # FIXME(ja): if image is cloudpipe, this breaks
+ if not vpn:
+ image = images.get(context, kwargs['image_id'])
+ # FIXME(ja): if image is vpn, this breaks
# get defaults from imagestore
image_id = image['imageId']
kernel_id = image.get('kernelId', FLAGS.default_kernel)
@@ -511,11 +477,10 @@ class CloudController(object):
ramdisk_id = kwargs.get('ramdisk_id', ramdisk_id)
# make sure we have access to kernel and ramdisk
- self._get_image(context, kernel_id)
- self._get_image(context, ramdisk_id)
+ images.get(context, kernel_id)
+ images.get(context, ramdisk_id)
logging.debug("Going to run instances...")
- reservation_id = utils.generate_uid('r')
launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
key_data = None
if kwargs.has_key('key_name'):
@@ -524,103 +489,117 @@ class CloudController(object):
raise exception.ApiError('Key Pair %s not found' %
kwargs['key_name'])
key_data = key_pair.public_key
- network_topic = self._get_network_topic(context)
+
# TODO: Get the real security group of launch in here
security_group = "default"
+
+ reservation_id = utils.generate_uid('r')
+ base_options = {}
+ base_options['image_id'] = image_id
+ base_options['kernel_id'] = kernel_id
+ base_options['ramdisk_id'] = ramdisk_id
+ base_options['reservation_id'] = reservation_id
+ base_options['key_data'] = key_data
+ base_options['key_name'] = kwargs.get('key_name', None)
+ base_options['user_id'] = context.user.id
+ base_options['project_id'] = context.project.id
+ base_options['user_data'] = kwargs.get('user_data', '')
+ base_options['instance_type'] = kwargs.get('instance_type', 'm1.small')
+ base_options['security_group'] = security_group
+
for num in range(int(kwargs['max_count'])):
- is_vpn = False
- if image_id == FLAGS.vpn_image_id:
- is_vpn = True
- inst = self.instdir.new()
- allocate_data = rpc.call(network_topic,
- {"method": "allocate_fixed_ip",
- "args": {"user_id": context.user.id,
- "project_id": context.project.id,
- "security_group": security_group,
- "is_vpn": is_vpn,
- "hostname": inst.instance_id}})
- inst['image_id'] = image_id
- inst['kernel_id'] = kernel_id
- inst['ramdisk_id'] = ramdisk_id
- inst['user_data'] = kwargs.get('user_data', '')
- inst['instance_type'] = kwargs.get('instance_type', 'm1.small')
- inst['reservation_id'] = reservation_id
- inst['launch_time'] = launch_time
- inst['key_data'] = key_data or ''
- inst['key_name'] = kwargs.get('key_name', '')
- inst['user_id'] = context.user.id
- inst['project_id'] = context.project.id
- inst['ami_launch_index'] = num
- inst['security_group'] = security_group
- inst['hostname'] = inst.instance_id
- for (key, value) in allocate_data.iteritems():
- inst[key] = value
-
- inst.save()
+ instance_ref = db.instance_create(context, base_options)
+ inst_id = instance_ref['id']
+
+ inst = {}
+ inst['mac_address'] = utils.generate_mac()
+ inst['launch_index'] = num
+ inst['hostname'] = instance_ref['str_id']
+ db.instance_update(context, inst_id, inst)
+ address = self.network_manager.allocate_fixed_ip(context,
+ inst_id,
+ vpn)
+
+ # TODO(vish): This probably should be done in the scheduler
+ # network is setup when host is assigned
+ network_topic = self._get_network_topic(context)
+ rpc.call(network_topic,
+ {"method": "setup_fixed_ip",
+ "args": {"context": None,
+ "address": address}})
+
rpc.cast(FLAGS.compute_topic,
{"method": "run_instance",
- "args": {"instance_id": inst.instance_id}})
- logging.debug("Casting to node for %s's instance with IP of %s" %
- (context.user.name, inst['private_dns_name']))
- # TODO: Make Network figure out the network name from ip.
+ "args": {"context": None,
+ "instance_id": inst_id}})
+ logging.debug("Casting to node for %s/%s's instance %s" %
+ (context.project.name, context.user.name, inst_id))
return self._format_run_instances(context, reservation_id)
+
def terminate_instances(self, context, instance_id, **kwargs):
logging.debug("Going to start terminating instances")
- network_topic = self._get_network_topic(context)
- for i in instance_id:
- logging.debug("Going to try and terminate %s" % i)
+ for id_str in instance_id:
+ logging.debug("Going to try and terminate %s" % id_str)
try:
- instance = self._get_instance(context, i)
+ instance_ref = db.instance_get_by_str(context, id_str)
except exception.NotFound:
logging.warning("Instance %s was not found during terminate"
- % i)
+ % id_str)
continue
- elastic_ip = network_model.get_public_ip_for_instance(i)
- if elastic_ip:
- logging.debug("Disassociating address %s" % elastic_ip)
- # NOTE(vish): Right now we don't really care if the ip is
- # disassociated. We may need to worry about
- # checking this later. Perhaps in the scheduler?
- rpc.cast(network_topic,
- {"method": "disassociate_elastic_ip",
- "args": {"elastic_ip": elastic_ip}})
- fixed_ip = instance.get('private_dns_name', None)
- if fixed_ip:
- logging.debug("Deallocating address %s" % fixed_ip)
+ # FIXME(ja): where should network deallocate occur?
+ address = db.instance_get_floating_address(context,
+ instance_ref['id'])
+ if address:
+ logging.debug("Disassociating address %s" % address)
# NOTE(vish): Right now we don't really care if the ip is
- # actually removed. We may need to worry about
+ # disassociated. We may need to worry about
# checking this later. Perhaps in the scheduler?
+ network_topic = yield self._get_network_topic(context)
rpc.cast(network_topic,
- {"method": "deallocate_fixed_ip",
- "args": {"fixed_ip": fixed_ip}})
-
- if instance.get('node_name', 'unassigned') != 'unassigned':
- # NOTE(joshua?): It's also internal default
- rpc.cast('%s.%s' % (FLAGS.compute_topic, instance['node_name']),
+ {"method": "disassociate_floating_ip",
+ "args": {"context": None,
+ "address": address}})
+
+ address = db.instance_get_fixed_address(context,
+ instance_ref['id'])
+ if address:
+ logging.debug("Deallocating address %s" % address)
+ # NOTE(vish): Currently, nothing needs to be done on the
+ # network node until release. If this changes,
+ # we will need to cast here.
+ self.network.deallocate_fixed_ip(context, address)
+
+ host = instance_ref['host']
+ if host:
+ rpc.cast(db.queue_get_for(context, FLAGS.compute_topic, host),
{"method": "terminate_instance",
- "args": {"instance_id": i}})
+ "args": {"context": None,
+ "instance_id": instance_ref['id']}})
else:
- instance.destroy()
+ db.instance_destroy(context, instance_ref['id'])
return True
def reboot_instances(self, context, instance_id, **kwargs):
"""instance_id is a list of instance ids"""
- for i in instance_id:
- instance = self._get_instance(context, i)
- rpc.cast('%s.%s' % (FLAGS.compute_topic, instance['node_name']),
- {"method": "reboot_instance",
- "args": {"instance_id": i}})
+ for id_str in instance_id:
+ instance_ref = db.instance_get_by_str(context, id_str)
+ host = instance_ref['host']
+ rpc.cast(db.queue_get_for(context, FLAGS.compute_topic, host),
+ {"method": "reboot_instance",
+ "args": {"context": None,
+ "instance_id": instance_ref['id']}})
return True
def delete_volume(self, context, volume_id, **kwargs):
# TODO: return error if not authorized
- volume = self._get_volume(context, volume_id)
- volume_node = volume['node_name']
- rpc.cast('%s.%s' % (FLAGS.volume_topic, volume_node),
+ volume_ref = db.volume_get_by_str(context, volume_id)
+ host = volume_ref['host']
+ rpc.cast(db.queue_get_for(context, FLAGS.volume_topic, host),
{"method": "delete_volume",
- "args": {"volume_id": volume_id}})
+ "args": {"context": None,
+ "volume_id": volume_ref['id']}})
return True
def describe_images(self, context, image_id=None, **kwargs):
@@ -664,22 +643,3 @@ class CloudController(object):
if not operation_type in ['add', 'remove']:
raise exception.ApiError('operation_type must be add or remove')
return images.modify(context, image_id, operation_type)
-
- def update_state(self, topic, value):
- """ accepts status reports from the queue and consolidates them """
- # TODO(jmc): if an instance has disappeared from
- # the node, call instance_death
- if topic == "instances":
- return True
- aggregate_state = getattr(self, topic)
- node_name = value.keys()[0]
- items = value[node_name]
-
- logging.debug("Updating %s state for %s" % (topic, node_name))
-
- for item_id in items.keys():
- if (aggregate_state.has_key('pending') and
- aggregate_state['pending'].has_key(item_id)):
- del aggregate_state['pending'][item_id]
- aggregate_state[node_name] = items
- return True
diff --git a/nova/api/ec2/images.py b/nova/api/ec2/images.py
index 2a88d66af..4579cd81a 100644
--- a/nova/api/ec2/images.py
+++ b/nova/api/ec2/images.py
@@ -18,7 +18,7 @@
"""
Proxy AMI-related calls from the cloud controller, to the running
-objectstore daemon.
+objectstore service.
"""
import json
@@ -26,6 +26,7 @@ import urllib
import boto.s3.connection
+from nova import exception
from nova import flags
from nova import utils
from nova.auth import manager
@@ -55,7 +56,6 @@ def register(context, image_location):
return image_id
-
def list(context, filter_list=[]):
""" return a list of all images that a user can see
@@ -71,6 +71,14 @@ def list(context, filter_list=[]):
return [i for i in result if i['imageId'] in filter_list]
return result
+def get(context, image_id):
+ """return a image object if the context has permissions"""
+ result = list(context, [image_id])
+ if not result:
+ raise exception.NotFound('Image %s could not be found' % image_id)
+ image = result[0]
+ return image
+
def deregister(context, image_id):
""" unregister an image """
diff --git a/nova/api/rackspace/servers.py b/nova/api/rackspace/servers.py
index 25d1fe9c8..1815f7523 100644
--- a/nova/api/rackspace/servers.py
+++ b/nova/api/rackspace/servers.py
@@ -14,27 +14,31 @@
# 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 time
+from nova import db
+from nova import flags
from nova import rpc
-from nova.compute import model as compute
+from nova import utils
from nova.api.rackspace import base
+FLAGS = flags.FLAGS
class Controller(base.Controller):
entity_name = 'servers'
def index(self, **kwargs):
instances = []
- for inst in compute.InstanceDirectory().all:
+ for inst in db.instance_get_all(None):
instances.append(instance_details(inst))
def show(self, **kwargs):
instance_id = kwargs['id']
- return compute.InstanceDirectory().get(instance_id)
+ return db.instance_get(None, instance_id)
def delete(self, **kwargs):
instance_id = kwargs['id']
- instance = compute.InstanceDirectory().get(instance_id)
+ instance = db.instance_get(None, instance_id)
if not instance:
raise ServerNotFound("The requested server was not found")
instance.destroy()
@@ -45,11 +49,11 @@ class Controller(base.Controller):
rpc.cast(
FLAGS.compute_topic, {
"method": "run_instance",
- "args": {"instance_id": inst.instance_id}})
+ "args": {"instance_id": inst['id']}})
def update(self, **kwargs):
instance_id = kwargs['id']
- instance = compute.InstanceDirectory().get(instance_id)
+ instance = db.instance_get(None, instance_id)
if not instance:
raise ServerNotFound("The requested server was not found")
instance.update(kwargs['server'])
@@ -59,7 +63,7 @@ class Controller(base.Controller):
"""Build instance data structure and save it to the data store."""
reservation = utils.generate_uid('r')
ltime = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
- inst = self.instdir.new()
+ inst = {}
inst['name'] = env['server']['name']
inst['image_id'] = env['server']['imageId']
inst['instance_type'] = env['server']['flavorId']
@@ -68,15 +72,8 @@ class Controller(base.Controller):
inst['reservation_id'] = reservation
inst['launch_time'] = ltime
inst['mac_address'] = utils.generate_mac()
- address = self.network.allocate_ip(
- inst['user_id'],
- inst['project_id'],
- mac=inst['mac_address'])
- inst['private_dns_name'] = str(address)
- inst['bridge_name'] = network.BridgedNetwork.get_network_for_project(
- inst['user_id'],
- inst['project_id'],
- 'default')['bridge_name']
+ inst_id = db.instance_create(None, inst)['id']
+ address = self.network_manager.allocate_fixed_ip(None, inst_id)
# key_data, key_name, ami_launch_index
# TODO(todd): key data or root password
inst.save()