summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaypipes@gmail.com <>2010-10-05 15:48:47 -0400
committerjaypipes@gmail.com <>2010-10-05 15:48:47 -0400
commitff1bbe1f674dd343202ac444ea462da788573880 (patch)
treea19c18e69d53d9e6087325dab88f3ddda68e8e40
parentb61f4ceff6ea5dbb4d9c63b9f7345c0b31785984 (diff)
parentf0db8b74ec894631fe29c2a33748b797758ecf50 (diff)
downloadnova-ff1bbe1f674dd343202ac444ea462da788573880.tar.gz
nova-ff1bbe1f674dd343202ac444ea462da788573880.tar.xz
nova-ff1bbe1f674dd343202ac444ea462da788573880.zip
Merge trunk
-rw-r--r--nova/api/ec2/cloud.py62
-rw-r--r--nova/compute/manager.py6
-rw-r--r--nova/db/api.py4
-rw-r--r--nova/db/sqlalchemy/api.py26
-rw-r--r--nova/db/sqlalchemy/models.py4
-rw-r--r--nova/server.py6
-rw-r--r--nova/tests/cloud_unittest.py3
-rw-r--r--nova/utils.py10
8 files changed, 84 insertions, 37 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 79c95788b..7f5f4c4e9 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -72,6 +72,20 @@ def _gen_key(context, user_id, key_name):
return {'private_key': private_key, 'fingerprint': fingerprint}
+def ec2_id_to_internal_id(ec2_id):
+ """Convert an ec2 ID (i-[base 36 number]) to an internal id (int)"""
+ return int(ec2_id[2:], 36)
+
+
+def internal_id_to_ec2_id(internal_id):
+ """Convert an internal ID (int) to an ec2 ID (i-[base 36 number])"""
+ digits = []
+ while internal_id != 0:
+ internal_id, remainder = divmod(internal_id, 36)
+ digits.append('0123456789abcdefghijklmnopqrstuvwxyz'[remainder])
+ return "i-%s" % ''.join(reversed(digits))
+
+
class CloudController(object):
""" CloudController provides the critical dispatch between
inbound API calls through the endpoint and messages
@@ -144,7 +158,7 @@ class CloudController(object):
},
'hostname': hostname,
'instance-action': 'none',
- 'instance-id': instance_ref['ec2_id'],
+ 'instance-id': internal_id_to_ec2_id(instance_ref['internal_id']),
'instance-type': instance_ref['instance_type'],
'local-hostname': hostname,
'local-ipv4': address,
@@ -244,9 +258,11 @@ class CloudController(object):
def delete_security_group(self, context, group_name, **kwargs):
return True
- def get_console_output(self, context, instance_id, **kwargs):
- # instance_id is passed in as a list of instances
- instance_ref = db.instance_get_by_ec2_id(context, instance_id[0])
+ def get_console_output(self, context, ec2_id_list, **kwargs):
+ # ec2_id_list is passed in as a list of instances
+ ec2_id = ec2_id_list[0]
+ internal_id = ec2_id_to_internal_id(ec2_id)
+ instance_ref = db.instance_get_by_ec2_id(context, internal_id)
return rpc.call('%s.%s' % (FLAGS.compute_topic,
instance_ref['host']),
{"method": "get_console_output",
@@ -326,7 +342,8 @@ class CloudController(object):
raise exception.ApiError("Volume status must be available")
if volume_ref['attach_status'] == "attached":
raise exception.ApiError("Volume is already attached")
- instance_ref = db.instance_get_by_ec2_id(context, instance_id)
+ internal_id = ec2_id_to_internal_id(instance_id)
+ instance_ref = db.instance_get_by_internal_id(context, internal_id)
host = instance_ref['host']
rpc.cast(db.queue_get_for(context, FLAGS.compute_topic, host),
{"method": "attach_volume",
@@ -360,9 +377,11 @@ class CloudController(object):
# If the instance doesn't exist anymore,
# then we need to call detach blind
db.volume_detached(context)
+ internal_id = instance_ref['internal_id']
+ ec2_id = internal_id_to_ec2_id(internal_id)
return {'attachTime': volume_ref['attach_time'],
'device': volume_ref['mountpoint'],
- 'instanceId': instance_ref['ec2_id'],
+ 'instanceId': internal_id,
'requestId': context.request_id,
'status': volume_ref['attach_status'],
'volumeId': volume_ref['id']}
@@ -411,7 +430,9 @@ class CloudController(object):
if instance['image_id'] == FLAGS.vpn_image_id:
continue
i = {}
- i['instanceId'] = instance['ec2_id']
+ internal_id = instance['internal_id']
+ ec2_id = internal_id_to_ec2_id(internal_id)
+ i['instanceId'] = ec2_id
i['imageId'] = instance['image_id']
i['instanceState'] = {
'code': instance['state'],
@@ -464,9 +485,10 @@ class CloudController(object):
instance_id = None
if (floating_ip_ref['fixed_ip']
and floating_ip_ref['fixed_ip']['instance']):
- instance_id = floating_ip_ref['fixed_ip']['instance']['ec2_id']
+ internal_id = floating_ip_ref['fixed_ip']['instance']['ec2_id']
+ ec2_id = internal_id_to_ec2_id(internal_id)
address_rv = {'public_ip': address,
- 'instance_id': instance_id}
+ 'instance_id': ec2_id}
if context.user.is_admin():
details = "%s (%s)" % (address_rv['instance_id'],
floating_ip_ref['project_id'])
@@ -498,8 +520,9 @@ class CloudController(object):
"floating_address": floating_ip_ref['address']}})
return {'releaseResponse': ["Address released."]}
- def associate_address(self, context, instance_id, public_ip, **kwargs):
- instance_ref = db.instance_get_by_ec2_id(context, instance_id)
+ def associate_address(self, context, ec2_id, public_ip, **kwargs):
+ internal_id = ec2_id_to_internal_id(ec2_id)
+ instance_ref = db.instance_get_by_internal_id(context, internal_id)
fixed_address = db.instance_get_fixed_address(context,
instance_ref['id'])
floating_ip_ref = db.floating_ip_get_by_address(context, public_ip)
@@ -610,7 +633,9 @@ class CloudController(object):
inst = {}
inst['mac_address'] = utils.generate_mac()
inst['launch_index'] = num
- inst['hostname'] = instance_ref['ec2_id']
+ internal_id = instance_ref['internal_id']
+ ec2_id = internal_id_to_ec2_id(internal_id)
+ inst['hostname'] = ec2_id
db.instance_update(context, inst_id, inst)
address = self.network_manager.allocate_fixed_ip(context,
inst_id,
@@ -634,12 +659,14 @@ class CloudController(object):
return self._format_run_instances(context, reservation_id)
- def terminate_instances(self, context, instance_id, **kwargs):
+ def terminate_instances(self, context, ec2_id_list, **kwargs):
logging.debug("Going to start terminating instances")
- for id_str in instance_id:
+ for id_str in ec2_id_list:
+ internal_id = ec2_id_to_internal_id(id_str)
logging.debug("Going to try and terminate %s" % id_str)
try:
- instance_ref = db.instance_get_by_ec2_id(context, id_str)
+ instance_ref = db.instance_get_by_internal_id(context,
+ internal_id)
except exception.NotFound:
logging.warning("Instance %s was not found during terminate"
% id_str)
@@ -688,7 +715,7 @@ class CloudController(object):
cloud.reboot(id_str, context=context)
return True
- def update_instance(self, context, instance_id, **kwargs):
+ def update_instance(self, context, ec2_id, **kwargs):
updatable_fields = ['display_name', 'display_description']
changes = {}
for field in updatable_fields:
@@ -696,7 +723,8 @@ class CloudController(object):
changes[field] = kwargs[field]
if changes:
db_context = {}
- inst = db.instance_get_by_ec2_id(db_context, instance_id)
+ internal_id = ec2_id_to_internal_id(ec2_id)
+ inst = db.instance_get_by_internal_id(db_context, internal_id)
db.instance_update(db_context, inst['id'], kwargs)
return True
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index f370ede8b..131fac406 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -67,7 +67,7 @@ class ComputeManager(manager.Manager):
def run_instance(self, context, instance_id, **_kwargs):
"""Launch a new instance with specified options."""
instance_ref = self.db.instance_get(context, instance_id)
- if instance_ref['ec2_id'] in self.driver.list_instances():
+ if instance_ref['internal_id'] in self.driver.list_instances():
raise exception.Error("Instance has already been created")
logging.debug("instance %s: starting...", instance_id)
project_id = instance_ref['project_id']
@@ -129,7 +129,7 @@ class ComputeManager(manager.Manager):
raise exception.Error(
'trying to reboot a non-running'
'instance: %s (state: %s excepted: %s)' %
- (instance_ref['ec2_id'],
+ (instance_ref['internal_id'],
instance_ref['state'],
power_state.RUNNING))
@@ -151,7 +151,7 @@ class ComputeManager(manager.Manager):
if FLAGS.connection_type == 'libvirt':
fname = os.path.abspath(os.path.join(FLAGS.instances_path,
- instance_ref['ec2_id'],
+ instance_ref['internal_id'],
'console.log'))
with open(fname, 'r') as f:
output = f.read()
diff --git a/nova/db/api.py b/nova/db/api.py
index a6d1f405a..0d324dc71 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -280,9 +280,9 @@ def instance_get_floating_address(context, instance_id):
return IMPL.instance_get_floating_address(context, instance_id)
-def instance_get_by_ec2_id(context, ec2_id):
+def instance_get_by_internal_id(context, internal_id):
"""Get an instance by ec2 id."""
- return IMPL.instance_get_by_ec2_id(context, ec2_id)
+ return IMPL.instance_get_by_internal_id(context, internal_id)
def instance_is_vpn(context, instance_id):
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index e0c6a34b8..870e7b1a5 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -525,6 +525,9 @@ def fixed_ip_update(context, address, values):
###################
+#TODO(gundlach): instance_create and volume_create are nearly identical
+#and should be refactored. I expect there are other copy-and-paste
+#functions between the two of them as well.
@require_context
def instance_create(context, values):
instance_ref = models.Instance()
@@ -533,10 +536,11 @@ def instance_create(context, values):
session = get_session()
with session.begin():
- while instance_ref.ec2_id == None:
- ec2_id = utils.generate_uid(instance_ref.__prefix__)
- if not instance_ec2_id_exists(context, ec2_id, session=session):
- instance_ref.ec2_id = ec2_id
+ while instance_ref.internal_id == None:
+ internal_id = utils.generate_uid(instance_ref.__prefix__)
+ if not instance_internal_id_exists(context, internal_id,
+ session=session):
+ instance_ref.internal_id = internal_id
instance_ref.save(session=session)
return instance_ref
@@ -635,31 +639,33 @@ def instance_get_all_by_reservation(context, reservation_id):
@require_context
-def instance_get_by_ec2_id(context, ec2_id):
+def instance_get_by_internal_id(context, internal_id):
session = get_session()
if is_admin_context(context):
result = session.query(models.Instance
- ).filter_by(ec2_id=ec2_id
+ ).filter_by(internal_id=internal_id
).filter_by(deleted=can_read_deleted(context)
).first()
elif is_user_context(context):
result = session.query(models.Instance
).filter_by(project_id=context.project.id
- ).filter_by(ec2_id=ec2_id
+ ).filter_by(internal_id=internal_id
).filter_by(deleted=False
).first()
if not result:
- raise exception.NotFound('Instance %s not found' % (ec2_id))
+ raise exception.NotFound('Instance %s not found' % (internal_id))
return result
@require_context
-def instance_ec2_id_exists(context, ec2_id, session=None):
+def instance_internal_id_exists(context, internal_id, session=None):
if not session:
session = get_session()
- return session.query(exists().where(models.Instance.id==ec2_id)).one()[0]
+ return session.query(
+ exists().where(models.Instance.internal_id==internal_id)
+ ).one()[0]
@require_context
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 673c8e94f..ebcb73413 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -152,7 +152,7 @@ class Instance(BASE, NovaBase):
__tablename__ = 'instances'
__prefix__ = 'i'
id = Column(Integer, primary_key=True)
- ec2_id = Column(String(10), unique=True)
+ internal_id = Column(Integer, unique=True)
admin_pass = Column(String(255))
@@ -169,7 +169,7 @@ class Instance(BASE, NovaBase):
@property
def name(self):
- return self.ec2_id
+ return self.internal_id
image_id = Column(String(255))
kernel_id = Column(String(255))
diff --git a/nova/server.py b/nova/server.py
index d4563bfe0..c58a15041 100644
--- a/nova/server.py
+++ b/nova/server.py
@@ -106,6 +106,7 @@ def serve(name, main):
def daemonize(args, name, main):
"""Does the work of daemonizing the process"""
logging.getLogger('amqplib').setLevel(logging.WARN)
+ files_to_keep = []
if FLAGS.daemonize:
logger = logging.getLogger()
formatter = logging.Formatter(
@@ -114,12 +115,14 @@ def daemonize(args, name, main):
syslog = logging.handlers.SysLogHandler(address='/dev/log')
syslog.setFormatter(formatter)
logger.addHandler(syslog)
+ files_to_keep.append(syslog.socket)
else:
if not FLAGS.logfile:
FLAGS.logfile = '%s.log' % name
logfile = logging.FileHandler(FLAGS.logfile)
logfile.setFormatter(formatter)
logger.addHandler(logfile)
+ files_to_keep.append(logfile.stream)
stdin, stdout, stderr = None, None, None
else:
stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
@@ -139,6 +142,7 @@ def daemonize(args, name, main):
stdout=stdout,
stderr=stderr,
uid=FLAGS.uid,
- gid=FLAGS.gid
+ gid=FLAGS.gid,
+ files_preserve=files_to_keep
):
main(args)
diff --git a/nova/tests/cloud_unittest.py b/nova/tests/cloud_unittest.py
index ae7dea1db..615e589cf 100644
--- a/nova/tests/cloud_unittest.py
+++ b/nova/tests/cloud_unittest.py
@@ -236,7 +236,8 @@ class CloudTestCase(test.TrialTestCase):
def test_update_of_instance_display_fields(self):
inst = db.instance_create({}, {})
- self.cloud.update_instance(self.context, inst['ec2_id'],
+ ec2_id = cloud.internal_id_to_ec2_id(inst['internal_id'])
+ self.cloud.update_instance(self.context, ec2_id,
display_name='c00l 1m4g3')
inst = db.instance_get({}, inst['id'])
self.assertEqual('c00l 1m4g3', inst['display_name'])
diff --git a/nova/utils.py b/nova/utils.py
index d18dd9843..b1699bda8 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -126,7 +126,15 @@ def runthis(prompt, cmd, check_exit_code = True):
def generate_uid(topic, size=8):
- return '%s-%s' % (topic, ''.join([random.choice('01234567890abcdefghijklmnopqrstuvwxyz') for x in xrange(size)]))
+ if topic == "i":
+ # Instances have integer internal ids.
+ #TODO(gundlach): We should make this more than 32 bits, but we need to
+ #figure out how to make the DB happy with 64 bit integers.
+ return random.randint(0, 2**32-1)
+ else:
+ characters = '01234567890abcdefghijklmnopqrstuvwxyz'
+ choices = [random.choice(characters) for x in xrange(size)]
+ return '%s-%s' % (topic, ''.join(choices))
def generate_mac():