From 1395690e99c41aa14e776e4b94054fde29856c60 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sat, 14 Aug 2010 18:04:43 -0700 Subject: got run_tests.py to run (with many failed tests) --- nova/compute/model.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/model.py b/nova/compute/model.py index 266a93b9a..54d816a9c 100644 --- a/nova/compute/model.py +++ b/nova/compute/model.py @@ -63,13 +63,11 @@ class InstanceDirectory(object): def __getitem__(self, item): return self.get(item) - @datastore.absorb_connection_error def by_project(self, project): """returns a list of instance objects for a project""" for instance_id in datastore.Redis.instance().smembers('project:%s:instances' % project): yield Instance(instance_id) - @datastore.absorb_connection_error def by_node(self, node): """returns a list of instances for a node""" for instance_id in datastore.Redis.instance().smembers('node:%s:instances' % node): @@ -90,12 +88,10 @@ class InstanceDirectory(object): """returns the instance a volume is attached to""" pass - @datastore.absorb_connection_error def exists(self, instance_id): return datastore.Redis.instance().sismember('instances', instance_id) @property - @datastore.absorb_connection_error def all(self): """returns a list of all instances""" for instance_id in datastore.Redis.instance().smembers('instances'): @@ -107,7 +103,7 @@ class InstanceDirectory(object): return self.get(instance_id) -class Instance(datastore.BasicModel): +class Instance(): """Wrapper around stored properties of an instance""" def __init__(self, instance_id): @@ -168,7 +164,7 @@ class Instance(datastore.BasicModel): self.unassociate_with("ip", self.state['private_dns_name']) return super(Instance, self).destroy() -class Host(datastore.BasicModel): +class Host(): """A Host is the machine where a Daemon is running.""" def __init__(self, hostname): @@ -185,7 +181,7 @@ class Host(datastore.BasicModel): return self.hostname -class Daemon(datastore.BasicModel): +class Daemon(): """A Daemon is a job (compute, api, network, ...) that runs on a host.""" def __init__(self, host_or_combined, binpath=None): @@ -235,7 +231,7 @@ class Daemon(datastore.BasicModel): for x in cls.associated_to("host", hostname): yield x -class SessionToken(datastore.BasicModel): +class SessionToken(): """This is a short-lived auth token that is passed through web requests""" def __init__(self, session_token): -- cgit From 5cc8d5839cdb20d588c808c2eac52889365e4454 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sat, 14 Aug 2010 21:24:26 -0700 Subject: more work on trying to get compute tests passing --- nova/compute/service.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index 820116453..ff27a9b88 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -38,7 +38,7 @@ from nova import process from nova import service from nova import utils from nova.compute import disk -from nova.compute import model +from nova import models from nova.compute import power_state from nova.compute.instance_types import INSTANCE_TYPES from nova.network import service as network_service @@ -61,7 +61,6 @@ class ComputeService(service.Service): super(ComputeService, self).__init__() self._instances = {} self._conn = virt_connection.get_connection() - self.instdir = model.InstanceDirectory() # TODO(joshua): This needs to ensure system state, specifically: modprobe aoe def noop(self): @@ -116,19 +115,14 @@ class ComputeService(service.Service): def run_instance(self, instance_id, **_kwargs): """ launch a new instance with specified options """ logging.debug("Starting instance %s..." % (instance_id)) - inst = self.instdir.get(instance_id) - # TODO: Get the real security group of launch in here - security_group = "default" + session = models.create_session() + inst = session.query(models.Instance).filter_by(id=instance_id).first() # NOTE(vish): passing network type allows us to express the # network without making a call to network to find # out which type of network to setup - network_service.setup_compute_network( - inst.get('network_type', 'vlan'), - inst['user_id'], - inst['project_id'], - security_group) + network_service.setup_compute_network(inst) - inst['node_name'] = FLAGS.node_name + inst.node_name = FLAGS.node_name inst.save() # TODO(vish) check to make sure the availability zone matches new_inst = Instance(self._conn, name=instance_id, data=inst) -- cgit From 3ee748bb6f55ad341606919901c4c17a82d069fd Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sat, 14 Aug 2010 22:55:04 -0700 Subject: ComputeConnectionTestCase is almost working again --- nova/compute/service.py | 187 ++++++++++++++++-------------------------------- 1 file changed, 63 insertions(+), 124 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index ff27a9b88..dc6a93bdb 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -68,11 +68,15 @@ class ComputeService(service.Service): return defer.succeed('PONG') def get_instance(self, instance_id): - # inst = self.instdir.get(instance_id) - # return inst - if self.instdir.exists(instance_id): - return Instance.fromName(self._conn, instance_id) - return None + session = models.create_session() + return session.query(models.Instance).filter_by(id=instance_id).one() + + def update_state(self, instance_id): + session = models.create_session() + inst = session.query(models.Instance).filter_by(id=instance_id).one() + # FIXME(ja): include other fields from state? + inst.state = self._conn.get_info(instance_id)['state'] + session.flush() @exception.wrap_exception def adopt_instances(self): @@ -87,14 +91,6 @@ class ComputeService(service.Service): pass return defer.succeed(len(self._instances)) - @exception.wrap_exception - def describe_instances(self): - retval = {} - for inst in self.instdir.by_node(FLAGS.node_name): - retval[inst['instance_id']] = ( - Instance.fromName(self._conn, inst['instance_id'])) - return retval - @defer.inlineCallbacks def report_state(self, nodename, daemon): # TODO(termie): make this pattern be more elegant. -todd @@ -111,6 +107,7 @@ class ComputeService(service.Service): logging.exception("model server went away") yield + @defer.inlineCallbacks @exception.wrap_exception def run_instance(self, instance_id, **_kwargs): """ launch a new instance with specified options """ @@ -121,56 +118,82 @@ class ComputeService(service.Service): # network without making a call to network to find # out which type of network to setup network_service.setup_compute_network(inst) - inst.node_name = FLAGS.node_name - inst.save() + session.commit() + # TODO(vish) check to make sure the availability zone matches - new_inst = Instance(self._conn, name=instance_id, data=inst) - logging.info("Instances current state is %s", new_inst.state) - if new_inst.is_running(): - raise exception.Error("Instance is already running") - new_inst.spawn() + inst.set_state(power_state.NOSTATE, 'spawning') + session.commit() + try: + yield self._conn.spawn(inst) + except Exception, ex: + logging.debug(ex) + inst.set_state(power_state.SHUTDOWN) + + self.update_state(instance_id) + + @defer.inlineCallbacks @exception.wrap_exception def terminate_instance(self, instance_id): """ terminate an instance on this machine """ logging.debug("Got told to terminate instance %s" % instance_id) - instance = self.get_instance(instance_id) - # inst = self.instdir.get(instance_id) - if not instance: - raise exception.Error( - 'trying to terminate unknown instance: %s' % instance_id) - d = instance.destroy() - # d.addCallback(lambda x: inst.destroy()) - return d + session = models.create_session() + instance = session.query(models.Instance).filter_by(id=instance_id).one() + if instance.state == power_state.SHUTOFF: + # self.datamodel.destroy() FIXME: RE-ADD ????? + raise exception.Error('trying to destroy already destroyed' + ' instance: %s' % instance_id) + + instance.set_state(power_state.NOSTATE, 'shutting_down') + yield self._conn.destroy(instance) + # FIXME(ja): should we keep it in a terminated state for a bit? + session.delete(instance) + session.flush() + + @defer.inlineCallbacks @exception.wrap_exception def reboot_instance(self, instance_id): """ reboot an instance on this server KVM doesn't support reboot, so we terminate and restart """ + self.update_state(instance_id) instance = self.get_instance(instance_id) - if not instance: + + # FIXME(ja): this is only checking the model state - not state on disk? + if instance.state != power_state.RUNNING: raise exception.Error( - 'trying to reboot unknown instance: %s' % instance_id) - return instance.reboot() + 'trying to reboot a non-running' + 'instance: %s (state: %s excepted: %s)' % (instance.id, instance.state, power_state.RUNNING)) + + logging.debug('rebooting instance %s' % instance.id) + instance.set_state(power_state.NOSTATE, 'rebooting') + yield self._conn.reboot(instance) + self.update_state(instance_id) - @defer.inlineCallbacks @exception.wrap_exception def get_console_output(self, instance_id): """ send the console output for an instance """ + # FIXME: Abstract this for Xen + logging.debug("Getting console output for %s" % (instance_id)) - inst = self.instdir.get(instance_id) - instance = self.get_instance(instance_id) - if not instance: - raise exception.Error( - 'trying to get console log for unknown: %s' % instance_id) - rv = yield instance.console_output() + session = models.create_session() + inst = self.get_instance(instance_id) + + if FLAGS.connection_type == 'libvirt': + fname = os.path.abspath( + os.path.join(FLAGS.instances_path, inst.id, 'console.log')) + with open(fname, 'r') as f: + output = f.read() + else: + output = 'FAKE CONSOLE OUTPUT' + # TODO(termie): this stuff belongs in the API layer, no need to # munge the data we send to ourselves output = {"InstanceId" : instance_id, "Timestamp" : "2", - "output" : base64.b64encode(rv)} - defer.returnValue(output) + "output" : base64.b64encode(output)} + return output @defer.inlineCallbacks @exception.wrap_exception @@ -264,29 +287,6 @@ class Instance(object): self.datamodel.save() logging.debug("Finished init of Instance with id of %s" % name) - @classmethod - def fromName(cls, conn, name): - """ use the saved data for reloading the instance """ - instdir = model.InstanceDirectory() - instance = instdir.get(name) - return cls(conn=conn, name=name, data=instance) - - def set_state(self, state_code, state_description=None): - self.datamodel['state'] = state_code - if not state_description: - state_description = power_state.name(state_code) - self.datamodel['state_description'] = state_description - self.datamodel.save() - - @property - def state(self): - # it is a string in datamodel - return int(self.datamodel['state']) - - @property - def name(self): - return self.datamodel['name'] - def is_pending(self): return (self.state == power_state.NOSTATE or self.state == 'pending') @@ -297,64 +297,3 @@ class Instance(object): logging.debug("Instance state is: %s" % self.state) return (self.state == power_state.RUNNING or self.state == 'running') - def describe(self): - return self.datamodel - - def info(self): - result = self._conn.get_info(self.name) - result['node_name'] = FLAGS.node_name - return result - - def update_state(self): - self.datamodel.update(self.info()) - self.set_state(self.state) - self.datamodel.save() # Extra, but harmless - - @defer.inlineCallbacks - @exception.wrap_exception - def destroy(self): - if self.is_destroyed(): - self.datamodel.destroy() - raise exception.Error('trying to destroy already destroyed' - ' instance: %s' % self.name) - - self.set_state(power_state.NOSTATE, 'shutting_down') - yield self._conn.destroy(self) - self.datamodel.destroy() - - @defer.inlineCallbacks - @exception.wrap_exception - def reboot(self): - if not self.is_running(): - raise exception.Error( - 'trying to reboot a non-running' - 'instance: %s (state: %s)' % (self.name, self.state)) - - logging.debug('rebooting instance %s' % self.name) - self.set_state(power_state.NOSTATE, 'rebooting') - yield self._conn.reboot(self) - self.update_state() - - @defer.inlineCallbacks - @exception.wrap_exception - def spawn(self): - self.set_state(power_state.NOSTATE, 'spawning') - logging.debug("Starting spawn in Instance") - try: - yield self._conn.spawn(self) - except Exception, ex: - logging.debug(ex) - self.set_state(power_state.SHUTDOWN) - self.update_state() - - @exception.wrap_exception - def console_output(self): - # FIXME: Abstract this for Xen - if FLAGS.connection_type == 'libvirt': - fname = os.path.abspath( - os.path.join(self.datamodel['basepath'], 'console.log')) - with open(fname, 'r') as f: - console = f.read() - else: - console = 'FAKE CONSOLE OUTPUT' - return defer.succeed(console) -- cgit From 295a56c665be7b7461ff41141a93cffb79ab4909 Mon Sep 17 00:00:00 2001 From: Sleepsonthefloor Date: Sat, 14 Aug 2010 07:08:34 -0700 Subject: remove more direct session interactions --- nova/compute/service.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index dc6a93bdb..4e6a2c944 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -68,15 +68,13 @@ class ComputeService(service.Service): return defer.succeed('PONG') def get_instance(self, instance_id): - session = models.create_session() - return session.query(models.Instance).filter_by(id=instance_id).one() + return models.Instance.find(instance_id) def update_state(self, instance_id): - session = models.create_session() - inst = session.query(models.Instance).filter_by(id=instance_id).one() + inst = models.Instance.find(instance_id) # FIXME(ja): include other fields from state? inst.state = self._conn.get_info(instance_id)['state'] - session.flush() + inst.save() @exception.wrap_exception def adopt_instances(self): @@ -112,18 +110,17 @@ class ComputeService(service.Service): def run_instance(self, instance_id, **_kwargs): """ launch a new instance with specified options """ logging.debug("Starting instance %s..." % (instance_id)) - session = models.create_session() - inst = session.query(models.Instance).filter_by(id=instance_id).first() + inst = models.Instance.find(instance_id) # NOTE(vish): passing network type allows us to express the # network without making a call to network to find # out which type of network to setup network_service.setup_compute_network(inst) inst.node_name = FLAGS.node_name - session.commit() + inst.save() # TODO(vish) check to make sure the availability zone matches inst.set_state(power_state.NOSTATE, 'spawning') - session.commit() + inst.save() try: yield self._conn.spawn(inst) @@ -177,7 +174,6 @@ class ComputeService(service.Service): # FIXME: Abstract this for Xen logging.debug("Getting console output for %s" % (instance_id)) - session = models.create_session() inst = self.get_instance(instance_id) if FLAGS.connection_type == 'libvirt': -- cgit From 33de18633fc6bb5fae64869dfe9963bf81f7f167 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 15 Aug 2010 15:55:53 -0700 Subject: refactoring volume and some cleanup in model and compute --- nova/compute/service.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index 4e6a2c944..7f6f3ad6e 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -67,13 +67,10 @@ class ComputeService(service.Service): """ simple test of an AMQP message call """ return defer.succeed('PONG') - def get_instance(self, instance_id): - return models.Instance.find(instance_id) - def update_state(self, instance_id): inst = models.Instance.find(instance_id) # FIXME(ja): include other fields from state? - inst.state = self._conn.get_info(instance_id)['state'] + inst.state = self._conn.get_info(instance_id)['state'] inst.save() @exception.wrap_exception @@ -109,6 +106,8 @@ class ComputeService(service.Service): @exception.wrap_exception def run_instance(self, instance_id, **_kwargs): """ launch a new instance with specified options """ + if instance_id in self._conn.list_instances(): + raise exception.Error("Instance has already been created") logging.debug("Starting instance %s..." % (instance_id)) inst = models.Instance.find(instance_id) # NOTE(vish): passing network type allows us to express the @@ -135,19 +134,18 @@ class ComputeService(service.Service): def terminate_instance(self, instance_id): """ terminate an instance on this machine """ logging.debug("Got told to terminate instance %s" % instance_id) - session = models.create_session() - instance = session.query(models.Instance).filter_by(id=instance_id).one() + inst = models.Instance.find(instance_id) - if instance.state == power_state.SHUTOFF: + if inst.state == power_state.SHUTOFF: # self.datamodel.destroy() FIXME: RE-ADD ????? raise exception.Error('trying to destroy already destroyed' ' instance: %s' % instance_id) - instance.set_state(power_state.NOSTATE, 'shutting_down') - yield self._conn.destroy(instance) + inst.set_state(power_state.NOSTATE, 'shutting_down') + inst.save() + yield self._conn.destroy(inst) # FIXME(ja): should we keep it in a terminated state for a bit? - session.delete(instance) - session.flush() + inst.delete() @defer.inlineCallbacks @exception.wrap_exception @@ -155,7 +153,7 @@ class ComputeService(service.Service): """ reboot an instance on this server KVM doesn't support reboot, so we terminate and restart """ self.update_state(instance_id) - instance = self.get_instance(instance_id) + instance = models.Instance.find(instance_id) # FIXME(ja): this is only checking the model state - not state on disk? if instance.state != power_state.RUNNING: @@ -174,7 +172,7 @@ class ComputeService(service.Service): # FIXME: Abstract this for Xen logging.debug("Getting console output for %s" % (instance_id)) - inst = self.get_instance(instance_id) + inst = models.Instance.find(instance_id) if FLAGS.connection_type == 'libvirt': fname = os.path.abspath( -- cgit From fa70aefb00e487102564b92f6d32047dd8998054 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 16 Aug 2010 01:51:28 -0700 Subject: fix launching and describing instances to work with sqlalchemy --- nova/compute/libvirt.xml.template | 3 +- nova/compute/service.py | 77 ++++----------------------------------- 2 files changed, 8 insertions(+), 72 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/libvirt.xml.template b/nova/compute/libvirt.xml.template index 307f9d03a..17bd79b7c 100644 --- a/nova/compute/libvirt.xml.template +++ b/nova/compute/libvirt.xml.template @@ -1,7 +1,7 @@ %(name)s - hvm + hvm %(basepath)s/kernel %(basepath)s/ramdisk root=/dev/vda1 console=ttyS0 @@ -26,5 +26,4 @@ - %(nova)s diff --git a/nova/compute/service.py b/nova/compute/service.py index 7f6f3ad6e..b80ef3740 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -70,7 +70,7 @@ class ComputeService(service.Service): def update_state(self, instance_id): inst = models.Instance.find(instance_id) # FIXME(ja): include other fields from state? - inst.state = self._conn.get_info(instance_id)['state'] + inst.state = self._conn.get_info(inst.name)['state'] inst.save() @exception.wrap_exception @@ -106,7 +106,7 @@ class ComputeService(service.Service): @exception.wrap_exception def run_instance(self, instance_id, **_kwargs): """ launch a new instance with specified options """ - if instance_id in self._conn.list_instances(): + if str(instance_id) in self._conn.list_instances(): raise exception.Error("Instance has already been created") logging.debug("Starting instance %s..." % (instance_id)) inst = models.Instance.find(instance_id) @@ -119,12 +119,11 @@ class ComputeService(service.Service): # TODO(vish) check to make sure the availability zone matches inst.set_state(power_state.NOSTATE, 'spawning') - inst.save() try: yield self._conn.spawn(inst) - except Exception, ex: - logging.debug(ex) + except: + logging.exception("Failed to spawn instance %s" % inst.name) inst.set_state(power_state.SHUTDOWN) self.update_state(instance_id) @@ -142,7 +141,6 @@ class ComputeService(service.Service): ' instance: %s' % instance_id) inst.set_state(power_state.NOSTATE, 'shutting_down') - inst.save() yield self._conn.destroy(inst) # FIXME(ja): should we keep it in a terminated state for a bit? inst.delete() @@ -159,9 +157,9 @@ class ComputeService(service.Service): if instance.state != power_state.RUNNING: raise exception.Error( 'trying to reboot a non-running' - 'instance: %s (state: %s excepted: %s)' % (instance.id, instance.state, power_state.RUNNING)) + 'instance: %s (state: %s excepted: %s)' % (instance.name, instance.state, power_state.RUNNING)) - logging.debug('rebooting instance %s' % instance.id) + logging.debug('rebooting instance %s' % instance.name) instance.set_state(power_state.NOSTATE, 'rebooting') yield self._conn.reboot(instance) self.update_state(instance_id) @@ -176,7 +174,7 @@ class ComputeService(service.Service): if FLAGS.connection_type == 'libvirt': fname = os.path.abspath( - os.path.join(FLAGS.instances_path, inst.id, 'console.log')) + os.path.join(FLAGS.instances_path, inst.name, 'console.log')) with open(fname, 'r') as f: output = f.read() else: @@ -230,64 +228,3 @@ class Group(object): class ProductCode(object): def __init__(self, product_code): self.product_code = product_code - - -class Instance(object): - - NOSTATE = 0x00 - RUNNING = 0x01 - BLOCKED = 0x02 - PAUSED = 0x03 - SHUTDOWN = 0x04 - SHUTOFF = 0x05 - CRASHED = 0x06 - - def __init__(self, conn, name, data): - """ spawn an instance with a given name """ - self._conn = conn - # TODO(vish): this can be removed after data has been updated - # data doesn't seem to have a working iterator so in doesn't work - if data.get('owner_id', None) is not None: - data['user_id'] = data['owner_id'] - data['project_id'] = data['owner_id'] - self.datamodel = data - - size = data.get('instance_type', FLAGS.default_instance_type) - if size not in INSTANCE_TYPES: - raise exception.Error('invalid instance type: %s' % size) - - self.datamodel.update(INSTANCE_TYPES[size]) - - self.datamodel['name'] = name - self.datamodel['instance_id'] = name - self.datamodel['basepath'] = data.get( - 'basepath', os.path.abspath( - os.path.join(FLAGS.instances_path, self.name))) - self.datamodel['memory_kb'] = int(self.datamodel['memory_mb']) * 1024 - self.datamodel.setdefault('image_id', FLAGS.default_image) - self.datamodel.setdefault('kernel_id', FLAGS.default_kernel) - self.datamodel.setdefault('ramdisk_id', FLAGS.default_ramdisk) - self.datamodel.setdefault('project_id', self.datamodel['user_id']) - self.datamodel.setdefault('bridge_name', None) - #self.datamodel.setdefault('key_data', None) - #self.datamodel.setdefault('key_name', None) - #self.datamodel.setdefault('addressing_type', None) - - # TODO(joshua) - The ugly non-flat ones - self.datamodel['groups'] = data.get('security_group', 'default') - # TODO(joshua): Support product codes somehow - self.datamodel.setdefault('product_codes', None) - - self.datamodel.save() - logging.debug("Finished init of Instance with id of %s" % name) - - def is_pending(self): - return (self.state == power_state.NOSTATE or self.state == 'pending') - - def is_destroyed(self): - return self.state == power_state.SHUTOFF - - def is_running(self): - logging.debug("Instance state is: %s" % self.state) - return (self.state == power_state.RUNNING or self.state == 'running') - -- cgit From c41d9601555c78e3c91fb481fdfb3d50ffdf440b Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 17 Aug 2010 19:41:17 -0700 Subject: progress on tests passing --- nova/compute/service.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index 13507a1bb..708134072 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -25,25 +25,19 @@ Compute Service: """ import base64 -import json import logging import os -import sys from twisted.internet import defer -from twisted.internet import task from nova import exception from nova import flags from nova import process from nova import service from nova import utils -from nova.compute import disk from nova import models from nova.compute import power_state -from nova.compute.instance_types import INSTANCE_TYPES from nova.network import service as network_service -from nova.objectstore import image # for image_path flag from nova.virt import connection as virt_connection from nova.volume import service as volume_service @@ -107,14 +101,15 @@ class ComputeService(service.Service): @exception.wrap_exception def run_instance(self, instance_id, **_kwargs): """ launch a new instance with specified options """ - if str(instance_id) in self._conn.list_instances(): + inst = models.Instance.find(instance_id) + if inst.name in self._conn.list_instances(): raise exception.Error("Instance has already been created") logging.debug("Starting instance %s..." % (instance_id)) inst = models.Instance.find(instance_id) # NOTE(vish): passing network type allows us to express the # network without making a call to network to find # out which type of network to setup - network_service.setup_compute_network(inst) + network_service.setup_compute_network(inst.project_id) inst.node_name = FLAGS.node_name inst.save() -- cgit From a74f2a3ca4e26c451a002f9a89f3ba4ac4a083c4 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 18 Aug 2010 18:32:08 -0700 Subject: fix report state --- nova/compute/service.py | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index 708134072..3909c8245 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -81,22 +81,6 @@ class ComputeService(service.Service): pass return defer.succeed(len(self._instances)) - @defer.inlineCallbacks - def report_state(self, nodename, daemon): - # TODO(termie): make this pattern be more elegant. -todd - try: - record = model.Daemon(nodename, daemon) - record.heartbeat() - if getattr(self, "model_disconnected", False): - self.model_disconnected = False - logging.error("Recovered model server connection!") - - except model.ConnectionError, ex: - if not getattr(self, "model_disconnected", False): - self.model_disconnected = True - logging.exception("model server went away") - yield - @defer.inlineCallbacks @exception.wrap_exception def run_instance(self, instance_id, **_kwargs): @@ -214,13 +198,3 @@ class ComputeService(service.Service): "sudo virsh detach-disk %s %s " % (instance_id, target)) volume.finish_detach() defer.returnValue(True) - - -class Group(object): - def __init__(self, group_id): - self.group_id = group_id - - -class ProductCode(object): - def __init__(self, product_code): - self.product_code = product_code -- cgit From a92465922fb74ca2c9b392e1c1b7ed5b5e306a76 Mon Sep 17 00:00:00 2001 From: andy Date: Thu, 19 Aug 2010 12:28:45 +0200 Subject: Data abstraction for compute service --- nova/compute/service.py | 144 ++++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 71 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index 3909c8245..7a2cb277d 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -30,6 +30,7 @@ import os from twisted.internet import defer +from nova import db from nova import exception from nova import flags from nova import process @@ -44,7 +45,7 @@ from nova.volume import service as volume_service FLAGS = flags.FLAGS flags.DEFINE_string('instances_path', utils.abspath('../instances'), - 'where instances are stored on disk') + 'where instances are stored on disk') class ComputeService(service.Service): @@ -52,109 +53,107 @@ class ComputeService(service.Service): Manages the running instances. """ def __init__(self): - """ load configuration options for this node and connect to the hypervisor""" + """Load configuration options and connect to the hypervisor.""" super(ComputeService, self).__init__() self._instances = {} self._conn = virt_connection.get_connection() - # TODO(joshua): This needs to ensure system state, specifically: modprobe aoe + # TODO(joshua): This needs to ensure system state, specifically + # modprobe aoe def noop(self): - """ simple test of an AMQP message call """ + """Simple test of an AMQP message call.""" return defer.succeed('PONG') - def update_state(self, instance_id): - inst = models.Instance.find(instance_id) + def update_state(self, instance_id, context): # FIXME(ja): include other fields from state? - inst.state = self._conn.get_info(inst.name)['state'] - inst.save() - - @exception.wrap_exception - def adopt_instances(self): - """ if there are instances already running, adopt them """ - return defer.succeed(0) - instance_names = self._conn.list_instances() - for name in instance_names: - try: - new_inst = Instance.fromName(self._conn, name) - new_inst.update_state() - except: - pass - return defer.succeed(len(self._instances)) + instance_ref = db.instance_get(context, instance_id) + state = self._conn.get_info(instance_ref.name)['state'] + db.instance_state(context, instance_id, state) @defer.inlineCallbacks @exception.wrap_exception - def run_instance(self, instance_id, **_kwargs): - """ launch a new instance with specified options """ - inst = models.Instance.find(instance_id) - if inst.name in self._conn.list_instances(): + def run_instance(self, instance_id, context=None, **_kwargs): + """Launch a new instance with specified options.""" + instance_ref = db.instance_get(context, instance_id) + if instance_ref['name'] in self._conn.list_instances(): raise exception.Error("Instance has already been created") logging.debug("Starting instance %s..." % (instance_id)) - inst = models.Instance.find(instance_id) + # NOTE(vish): passing network type allows us to express the # network without making a call to network to find # out which type of network to setup - network_service.setup_compute_network(inst.project_id) - inst.node_name = FLAGS.node_name - inst.save() + network_service.setup_compute_network(instance_ref['project_id']) + db.instance_update(context, instance_id, {'node_name': FLAGS.node_name}) # TODO(vish) check to make sure the availability zone matches - inst.set_state(power_state.NOSTATE, 'spawning') + db.instance_state(context, instance_id, power_state.NOSTATE, 'spawning') try: - yield self._conn.spawn(inst) + yield self._conn.spawn(instance_ref) except: - logging.exception("Failed to spawn instance %s" % inst.name) - inst.set_state(power_state.SHUTDOWN) + logging.exception("Failed to spawn instance %s" % + instance_ref['name']) + db.instance_state(context, instance_id, power_state.SHUTDOWN) - self.update_state(instance_id) + self.update_state(instance_id, context) @defer.inlineCallbacks @exception.wrap_exception - def terminate_instance(self, instance_id): - """ terminate an instance on this machine """ + def terminate_instance(self, instance_id, context=None): + """Terminate an instance on this machine.""" logging.debug("Got told to terminate instance %s" % instance_id) - inst = models.Instance.find(instance_id) + instance_ref = db.instance_get(context, instance_id) - if inst.state == power_state.SHUTOFF: - # self.datamodel.destroy() FIXME: RE-ADD ????? + if instance_ref['state'] == power_state.SHUTOFF: + # self.datamodel.destroy() FIXME: RE-ADD? raise exception.Error('trying to destroy already destroyed' ' instance: %s' % instance_id) - inst.set_state(power_state.NOSTATE, 'shutting_down') - yield self._conn.destroy(inst) + db.instance_state( + context, instance_id, power_state.NOSTATE, 'shutting_down') + yield self._conn.destroy(instance_ref) + # FIXME(ja): should we keep it in a terminated state for a bit? - inst.delete() + db.instance_destroy(context, instance_id) @defer.inlineCallbacks @exception.wrap_exception - def reboot_instance(self, instance_id): - """ reboot an instance on this server - KVM doesn't support reboot, so we terminate and restart """ - self.update_state(instance_id) - instance = models.Instance.find(instance_id) + def reboot_instance(self, instance_id, context=None): + """Reboot an instance on this server. + + KVM doesn't support reboot, so we terminate and restart. + + """ + self.update_state(instance_id, context) + instance_ref = db.instance_get(context, instance_id) # FIXME(ja): this is only checking the model state - not state on disk? - if instance.state != power_state.RUNNING: + if instance_ref['state'] != power_state.RUNNING: raise exception.Error( 'trying to reboot a non-running' - 'instance: %s (state: %s excepted: %s)' % (instance.name, instance.state, power_state.RUNNING)) + 'instance: %s (state: %s excepted: %s)' % + (instance_ref['name'], + instance_ref['state'], + power_state.RUNNING)) - logging.debug('rebooting instance %s' % instance.name) - instance.set_state(power_state.NOSTATE, 'rebooting') - yield self._conn.reboot(instance) - self.update_state(instance_id) + logging.debug('rebooting instance %s' % instance_ref['name']) + db.instance_state( + context, instance_id, power_state.NOSTATE, 'rebooting') + yield self._conn.reboot(instance_ref) + self.update_state(instance_id, context) @exception.wrap_exception - def get_console_output(self, instance_id): - """ send the console output for an instance """ + def get_console_output(self, instance_id, context=None): + """Send the console output for an instance.""" # FIXME: Abstract this for Xen logging.debug("Getting console output for %s" % (instance_id)) - inst = models.Instance.find(instance_id) + instance_ref = db.instance_get(context, instance_id) if FLAGS.connection_type == 'libvirt': - fname = os.path.abspath( - os.path.join(FLAGS.instances_path, inst.name, 'console.log')) + fname = os.path.abspath(os.path.join(FLAGS.instances_path, + instance_ref['name'], + 'console.log')) with open(fname, 'r') as f: output = f.read() else: @@ -169,32 +168,35 @@ class ComputeService(service.Service): @defer.inlineCallbacks @exception.wrap_exception - def attach_volume(self, instance_id = None, - volume_id = None, mountpoint = None): - volume = volume_service.get_volume(volume_id) + def attach_volume(self, instance_id=None, volume_id=None, mountpoint=None, + context=None): + """Attach a volume to an instance.""" + # TODO(termie): check that instance_id exists + volume_ref = volume_get(context, volume_id) yield self._init_aoe() yield process.simple_execute( "sudo virsh attach-disk %s /dev/etherd/%s %s" % (instance_id, volume['aoe_device'], mountpoint.rpartition('/dev/')[2])) - volume.finish_attach() + volume_attached(context, volume_id) defer.returnValue(True) - @defer.inlineCallbacks - def _init_aoe(self): - yield process.simple_execute("sudo aoe-discover") - yield process.simple_execute("sudo aoe-stat") - @defer.inlineCallbacks @exception.wrap_exception - def detach_volume(self, instance_id, volume_id): - """ detach a volume from an instance """ + def detach_volume(self, instance_id, volume_id, context=None): + """Detach a volume from an instance.""" # despite the documentation, virsh detach-disk just wants the device # name without the leading /dev/ - volume = volume_service.get_volume(volume_id) + # TODO(termie): check that instance_id exists + volume_ref = volume_get(context, volume_id) target = volume['mountpoint'].rpartition('/dev/')[2] yield process.simple_execute( "sudo virsh detach-disk %s %s " % (instance_id, target)) - volume.finish_detach() + volume_detached(context, volume_id) defer.returnValue(True) + + @defer.inlineCallbacks + def _init_aoe(self): + yield process.simple_execute("sudo aoe-discover") + yield process.simple_execute("sudo aoe-stat") -- cgit From a5a1ba53fdd122f85e61d74756d19d732805a357 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 19 Aug 2010 13:58:43 -0700 Subject: move volume code into datalayer and cleanup --- nova/compute/service.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index 7a2cb277d..dd16484fe 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -36,11 +36,9 @@ from nova import flags from nova import process from nova import service from nova import utils -from nova import models from nova.compute import power_state from nova.network import service as network_service from nova.virt import connection as virt_connection -from nova.volume import service as volume_service FLAGS = flags.FLAGS @@ -122,7 +120,7 @@ class ComputeService(service.Service): """Reboot an instance on this server. KVM doesn't support reboot, so we terminate and restart. - + """ self.update_state(instance_id, context) instance_ref = db.instance_get(context, instance_id) @@ -172,14 +170,14 @@ class ComputeService(service.Service): context=None): """Attach a volume to an instance.""" # TODO(termie): check that instance_id exists - volume_ref = volume_get(context, volume_id) + volume_ref = db.volume_get(context, volume_id) yield self._init_aoe() yield process.simple_execute( "sudo virsh attach-disk %s /dev/etherd/%s %s" % (instance_id, - volume['aoe_device'], + volume_ref['aoe_device'], mountpoint.rpartition('/dev/')[2])) - volume_attached(context, volume_id) + db.volume_attached(context, volume_id) defer.returnValue(True) @defer.inlineCallbacks @@ -189,14 +187,15 @@ class ComputeService(service.Service): # despite the documentation, virsh detach-disk just wants the device # name without the leading /dev/ # TODO(termie): check that instance_id exists - volume_ref = volume_get(context, volume_id) - target = volume['mountpoint'].rpartition('/dev/')[2] + volume_ref = db.volume_get(context, volume_id) + target = volume_ref['mountpoint'].rpartition('/dev/')[2] yield process.simple_execute( "sudo virsh detach-disk %s %s " % (instance_id, target)) - volume_detached(context, volume_id) + db.volume_detached(context, volume_id) defer.returnValue(True) @defer.inlineCallbacks def _init_aoe(self): + # TODO(vish): these shell calls should move into a different layer. yield process.simple_execute("sudo aoe-discover") yield process.simple_execute("sudo aoe-stat") -- cgit From 548ae499c29341d58ad18ed5262f965ad0b5b0a9 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 24 Aug 2010 19:15:35 -0700 Subject: fix setup compute network --- nova/compute/service.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index dd16484fe..a44f17a69 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -77,10 +77,7 @@ class ComputeService(service.Service): raise exception.Error("Instance has already been created") logging.debug("Starting instance %s..." % (instance_id)) - # NOTE(vish): passing network type allows us to express the - # network without making a call to network to find - # out which type of network to setup - network_service.setup_compute_network(instance_ref['project_id']) + network_service.setup_compute_network(context, instance_ref['project_id']) db.instance_update(context, instance_id, {'node_name': FLAGS.node_name}) # TODO(vish) check to make sure the availability zone matches -- cgit From 674a5dae7c0630aef346e22950706db0caeb244b Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 25 Aug 2010 13:14:49 -0700 Subject: more data layer breakouts, lots of fixes to cloud.py --- nova/compute/service.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index a44f17a69..877246ef6 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -73,7 +73,7 @@ class ComputeService(service.Service): def run_instance(self, instance_id, context=None, **_kwargs): """Launch a new instance with specified options.""" instance_ref = db.instance_get(context, instance_id) - if instance_ref['name'] in self._conn.list_instances(): + if instance_ref['str_id'] in self._conn.list_instances(): raise exception.Error("Instance has already been created") logging.debug("Starting instance %s..." % (instance_id)) @@ -87,7 +87,7 @@ class ComputeService(service.Service): yield self._conn.spawn(instance_ref) except: logging.exception("Failed to spawn instance %s" % - instance_ref['name']) + instance_ref['str_id']) db.instance_state(context, instance_id, power_state.SHUTDOWN) self.update_state(instance_id, context) @@ -127,11 +127,11 @@ class ComputeService(service.Service): raise exception.Error( 'trying to reboot a non-running' 'instance: %s (state: %s excepted: %s)' % - (instance_ref['name'], + (instance_ref['str_id'], instance_ref['state'], power_state.RUNNING)) - logging.debug('rebooting instance %s' % instance_ref['name']) + logging.debug('rebooting instance %s' % instance_ref['str_id']) db.instance_state( context, instance_id, power_state.NOSTATE, 'rebooting') yield self._conn.reboot(instance_ref) @@ -147,7 +147,7 @@ class ComputeService(service.Service): if FLAGS.connection_type == 'libvirt': fname = os.path.abspath(os.path.join(FLAGS.instances_path, - instance_ref['name'], + instance_ref['str_id'], 'console.log')) with open(fname, 'r') as f: output = f.read() -- cgit From 0828326898e3bc219c8205e27a3cc942e2790934 Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Wed, 25 Aug 2010 16:27:01 -0400 Subject: Use compute.instance_types for flavor data instead of a FlavorService --- nova/compute/instance_types.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 439be3c7d..0102bae54 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -21,10 +21,10 @@ The built-in instance properties. """ -INSTANCE_TYPES = {} -INSTANCE_TYPES['m1.tiny'] = {'memory_mb': 512, 'vcpus': 1, 'local_gb': 0} -INSTANCE_TYPES['m1.small'] = {'memory_mb': 1024, 'vcpus': 1, 'local_gb': 10} -INSTANCE_TYPES['m1.medium'] = {'memory_mb': 2048, 'vcpus': 2, 'local_gb': 10} -INSTANCE_TYPES['m1.large'] = {'memory_mb': 4096, 'vcpus': 4, 'local_gb': 10} -INSTANCE_TYPES['m1.xlarge'] = {'memory_mb': 8192, 'vcpus': 4, 'local_gb': 10} -INSTANCE_TYPES['c1.medium'] = {'memory_mb': 2048, 'vcpus': 4, 'local_gb': 10} +INSTANCE_TYPES = { + 'm1.tiny': dict(memory_mb=512, vcpus=1, local_gb=0, flavorid=1), + 'm1.small': dict(memory_mb=1024, vcpus=1, local_gb=10, flavorid=2), + 'm1.medium': dict(memory_mb=2048, vcpus=2, local_gb=10, flavorid=3), + 'm1.large': dict(memory_mb=4096, vcpus=4, local_gb=10, flavorid=4), + 'm1.xlarge': dict(memory_mb=8192, vcpus=4, local_gb=10, flavorid=5), + 'c1.medium': dict(memory_mb=2048, vcpus=4, local_gb=10, flavorid=6)} -- cgit From fab0bbaca8d6cf34f131c4426463bf5c76a0477f Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 29 Aug 2010 18:53:47 -0700 Subject: tests pass --- nova/compute/service.py | 174 ++---------------------------------------------- 1 file changed, 4 insertions(+), 170 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py index 877246ef6..9bf498d03 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -17,182 +17,16 @@ # under the License. """ -Compute Service: - - Runs on each compute host, managing the - hypervisor using the virt module. - +Compute service allows rpc calls to the compute manager and reports state +to the database. """ -import base64 -import logging -import os - -from twisted.internet import defer - -from nova import db -from nova import exception -from nova import flags -from nova import process from nova import service -from nova import utils -from nova.compute import power_state -from nova.network import service as network_service -from nova.virt import connection as virt_connection - - -FLAGS = flags.FLAGS -flags.DEFINE_string('instances_path', utils.abspath('../instances'), - 'where instances are stored on disk') class ComputeService(service.Service): """ - Manages the running instances. + Compute Service automatically passes commands on to the Compute Manager """ - def __init__(self): - """Load configuration options and connect to the hypervisor.""" - super(ComputeService, self).__init__() - self._instances = {} - self._conn = virt_connection.get_connection() - # TODO(joshua): This needs to ensure system state, specifically - # modprobe aoe - - def noop(self): - """Simple test of an AMQP message call.""" - return defer.succeed('PONG') - - def update_state(self, instance_id, context): - # FIXME(ja): include other fields from state? - instance_ref = db.instance_get(context, instance_id) - state = self._conn.get_info(instance_ref.name)['state'] - db.instance_state(context, instance_id, state) - - @defer.inlineCallbacks - @exception.wrap_exception - def run_instance(self, instance_id, context=None, **_kwargs): - """Launch a new instance with specified options.""" - instance_ref = db.instance_get(context, instance_id) - if instance_ref['str_id'] in self._conn.list_instances(): - raise exception.Error("Instance has already been created") - logging.debug("Starting instance %s..." % (instance_id)) - - network_service.setup_compute_network(context, instance_ref['project_id']) - db.instance_update(context, instance_id, {'node_name': FLAGS.node_name}) - - # TODO(vish) check to make sure the availability zone matches - db.instance_state(context, instance_id, power_state.NOSTATE, 'spawning') - - try: - yield self._conn.spawn(instance_ref) - except: - logging.exception("Failed to spawn instance %s" % - instance_ref['str_id']) - db.instance_state(context, instance_id, power_state.SHUTDOWN) - - self.update_state(instance_id, context) - - @defer.inlineCallbacks - @exception.wrap_exception - def terminate_instance(self, instance_id, context=None): - """Terminate an instance on this machine.""" - logging.debug("Got told to terminate instance %s" % instance_id) - instance_ref = db.instance_get(context, instance_id) - - if instance_ref['state'] == power_state.SHUTOFF: - # self.datamodel.destroy() FIXME: RE-ADD? - raise exception.Error('trying to destroy already destroyed' - ' instance: %s' % instance_id) - - db.instance_state( - context, instance_id, power_state.NOSTATE, 'shutting_down') - yield self._conn.destroy(instance_ref) - - # FIXME(ja): should we keep it in a terminated state for a bit? - db.instance_destroy(context, instance_id) - - @defer.inlineCallbacks - @exception.wrap_exception - def reboot_instance(self, instance_id, context=None): - """Reboot an instance on this server. - - KVM doesn't support reboot, so we terminate and restart. - - """ - self.update_state(instance_id, context) - instance_ref = db.instance_get(context, instance_id) - - # FIXME(ja): this is only checking the model state - not state on disk? - if instance_ref['state'] != power_state.RUNNING: - raise exception.Error( - 'trying to reboot a non-running' - 'instance: %s (state: %s excepted: %s)' % - (instance_ref['str_id'], - instance_ref['state'], - power_state.RUNNING)) - - logging.debug('rebooting instance %s' % instance_ref['str_id']) - db.instance_state( - context, instance_id, power_state.NOSTATE, 'rebooting') - yield self._conn.reboot(instance_ref) - self.update_state(instance_id, context) - - @exception.wrap_exception - def get_console_output(self, instance_id, context=None): - """Send the console output for an instance.""" - # FIXME: Abstract this for Xen - - logging.debug("Getting console output for %s" % (instance_id)) - instance_ref = db.instance_get(context, instance_id) - - if FLAGS.connection_type == 'libvirt': - fname = os.path.abspath(os.path.join(FLAGS.instances_path, - instance_ref['str_id'], - 'console.log')) - with open(fname, 'r') as f: - output = f.read() - else: - output = 'FAKE CONSOLE OUTPUT' - - # TODO(termie): this stuff belongs in the API layer, no need to - # munge the data we send to ourselves - output = {"InstanceId" : instance_id, - "Timestamp" : "2", - "output" : base64.b64encode(output)} - return output - - @defer.inlineCallbacks - @exception.wrap_exception - def attach_volume(self, instance_id=None, volume_id=None, mountpoint=None, - context=None): - """Attach a volume to an instance.""" - # TODO(termie): check that instance_id exists - volume_ref = db.volume_get(context, volume_id) - yield self._init_aoe() - yield process.simple_execute( - "sudo virsh attach-disk %s /dev/etherd/%s %s" % - (instance_id, - volume_ref['aoe_device'], - mountpoint.rpartition('/dev/')[2])) - db.volume_attached(context, volume_id) - defer.returnValue(True) - - @defer.inlineCallbacks - @exception.wrap_exception - def detach_volume(self, instance_id, volume_id, context=None): - """Detach a volume from an instance.""" - # despite the documentation, virsh detach-disk just wants the device - # name without the leading /dev/ - # TODO(termie): check that instance_id exists - volume_ref = db.volume_get(context, volume_id) - target = volume_ref['mountpoint'].rpartition('/dev/')[2] - yield process.simple_execute( - "sudo virsh detach-disk %s %s " % (instance_id, target)) - db.volume_detached(context, volume_id) - defer.returnValue(True) + pass - @defer.inlineCallbacks - def _init_aoe(self): - # TODO(vish): these shell calls should move into a different layer. - yield process.simple_execute("sudo aoe-discover") - yield process.simple_execute("sudo aoe-stat") -- cgit From a64149a8b148858414409a88f968408f9606891f Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 30 Aug 2010 17:53:59 -0700 Subject: pep8 cleanup --- nova/compute/model.py | 309 ------------------------------------------------ nova/compute/service.py | 1 - 2 files changed, 310 deletions(-) delete mode 100644 nova/compute/model.py (limited to 'nova/compute') diff --git a/nova/compute/model.py b/nova/compute/model.py deleted file mode 100644 index baa41c3e0..000000000 --- a/nova/compute/model.py +++ /dev/null @@ -1,309 +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. - -""" -Datastore Model objects for Compute Instances, with -InstanceDirectory manager. - -# Create a new instance? ->>> InstDir = InstanceDirectory() ->>> inst = InstDir.new() ->>> inst.destroy() -True ->>> inst = InstDir['i-123'] ->>> inst['ip'] = "192.168.0.3" ->>> inst['project_id'] = "projectA" ->>> inst.save() -True - ->>> InstDir['i-123'] - ->>> InstDir.all.next() - - ->>> inst.destroy() -True -""" - -import datetime -import uuid - -from nova import datastore -from nova import exception -from nova import flags -from nova import utils - - -FLAGS = flags.FLAGS - - -# TODO(todd): Implement this at the class level for Instance -class InstanceDirectory(object): - """an api for interacting with the global state of instances""" - - def get(self, instance_id): - """returns an instance object for a given id""" - return Instance(instance_id) - - def __getitem__(self, item): - return self.get(item) - - def by_project(self, project): - """returns a list of instance objects for a project""" - for instance_id in datastore.Redis.instance().smembers('project:%s:instances' % project): - yield Instance(instance_id) - - def by_node(self, node): - """returns a list of instances for a node""" - for instance_id in datastore.Redis.instance().smembers('node:%s:instances' % node): - yield Instance(instance_id) - - def by_ip(self, ip): - """returns an instance object that is using the IP""" - # NOTE(vish): The ip association should be just a single value, but - # to maintain consistency it is using the standard - # association and the ugly method for retrieving - # the first item in the set below. - result = datastore.Redis.instance().smembers('ip:%s:instances' % ip) - if not result: - return None - return Instance(list(result)[0]) - - def by_volume(self, volume_id): - """returns the instance a volume is attached to""" - pass - - def exists(self, instance_id): - return datastore.Redis.instance().sismember('instances', instance_id) - - @property - def all(self): - """returns a list of all instances""" - for instance_id in datastore.Redis.instance().smembers('instances'): - yield Instance(instance_id) - - def new(self): - """returns an empty Instance object, with ID""" - instance_id = utils.generate_uid('i') - return self.get(instance_id) - - -class Instance(): - """Wrapper around stored properties of an instance""" - - def __init__(self, instance_id): - """loads an instance from the datastore if exists""" - # set instance data before super call since it uses default_state - self.instance_id = instance_id - super(Instance, self).__init__() - - def default_state(self): - return {'state': 0, - 'state_description': 'pending', - 'instance_id': self.instance_id, - 'node_name': 'unassigned', - 'project_id': 'unassigned', - 'user_id': 'unassigned', - 'private_dns_name': 'unassigned'} - - @property - def identifier(self): - return self.instance_id - - @property - def project(self): - if self.state.get('project_id', None): - return self.state['project_id'] - return self.state.get('owner_id', 'unassigned') - - @property - def volumes(self): - """returns a list of attached volumes""" - pass - - @property - def reservation(self): - """Returns a reservation object""" - pass - - def save(self): - """Call into superclass to save object, then save associations""" - # NOTE(todd): doesn't track migration between projects/nodes, - # it just adds the first one - is_new = self.is_new_record() - node_set = (self.state['node_name'] != 'unassigned' and - self.initial_state.get('node_name', 'unassigned') - == 'unassigned') - success = super(Instance, self).save() - if success and is_new: - self.associate_with("project", self.project) - self.associate_with("ip", self.state['private_dns_name']) - if success and node_set: - self.associate_with("node", self.state['node_name']) - return True - - def destroy(self): - """Destroy associations, then destroy the object""" - self.unassociate_with("project", self.project) - self.unassociate_with("node", self.state['node_name']) - self.unassociate_with("ip", self.state['private_dns_name']) - return super(Instance, self).destroy() - -class Host(): - """A Host is the machine where a Daemon is running.""" - - def __init__(self, hostname): - """loads an instance from the datastore if exists""" - # set instance data before super call since it uses default_state - self.hostname = hostname - super(Host, self).__init__() - - def default_state(self): - return {"hostname": self.hostname} - - @property - def identifier(self): - return self.hostname - - -class Daemon(): - """A Daemon is a job (compute, api, network, ...) that runs on a host.""" - - def __init__(self, host_or_combined, binpath=None): - """loads an instance from the datastore if exists""" - # set instance data before super call since it uses default_state - # since loading from datastore expects a combined key that - # is equivilent to identifier, we need to expect that, while - # maintaining meaningful semantics (2 arguments) when creating - # from within other code like the bin/nova-* scripts - if binpath: - self.hostname = host_or_combined - self.binary = binpath - else: - self.hostname, self.binary = host_or_combined.split(":") - super(Daemon, self).__init__() - - def default_state(self): - return {"hostname": self.hostname, - "binary": self.binary, - "updated_at": utils.isotime() - } - - @property - def identifier(self): - return "%s:%s" % (self.hostname, self.binary) - - def save(self): - """Call into superclass to save object, then save associations""" - # NOTE(todd): this makes no attempt to destroy itsself, - # so after termination a record w/ old timestmap remains - success = super(Daemon, self).save() - if success: - self.associate_with("host", self.hostname) - return True - - def destroy(self): - """Destroy associations, then destroy the object""" - self.unassociate_with("host", self.hostname) - return super(Daemon, self).destroy() - - def heartbeat(self): - self['updated_at'] = utils.isotime() - return self.save() - - @classmethod - def by_host(cls, hostname): - for x in cls.associated_to("host", hostname): - yield x - - -class SessionToken(): - """This is a short-lived auth token that is passed through web requests""" - - def __init__(self, session_token): - self.token = session_token - self.default_ttl = FLAGS.auth_token_ttl - super(SessionToken, self).__init__() - - @property - def identifier(self): - return self.token - - def default_state(self): - now = datetime.datetime.utcnow() - diff = datetime.timedelta(seconds=self.default_ttl) - expires = now + diff - return {'user': None, 'session_type': None, 'token': self.token, - 'expiry': expires.strftime(utils.TIME_FORMAT)} - - def save(self): - """Call into superclass to save object, then save associations""" - if not self['user']: - raise exception.Invalid("SessionToken requires a User association") - success = super(SessionToken, self).save() - if success: - self.associate_with("user", self['user']) - return True - - @classmethod - def lookup(cls, key): - token = super(SessionToken, cls).lookup(key) - if token: - expires_at = utils.parse_isotime(token['expiry']) - if datetime.datetime.utcnow() >= expires_at: - token.destroy() - return None - return token - - @classmethod - def generate(cls, userid, session_type=None): - """make a new token for the given user""" - token = str(uuid.uuid4()) - while cls.lookup(token): - token = str(uuid.uuid4()) - instance = cls(token) - instance['user'] = userid - instance['session_type'] = session_type - instance.save() - return instance - - def update_expiry(self, **kwargs): - """updates the expirty attribute, but doesn't save""" - if not kwargs: - kwargs['seconds'] = self.default_ttl - time = datetime.datetime.utcnow() - diff = datetime.timedelta(**kwargs) - expires = time + diff - self['expiry'] = expires.strftime(utils.TIME_FORMAT) - - def is_expired(self): - now = datetime.datetime.utcnow() - expires = utils.parse_isotime(self['expiry']) - return expires <= now - - def ttl(self): - """number of seconds remaining before expiration""" - now = datetime.datetime.utcnow() - expires = utils.parse_isotime(self['expiry']) - delta = expires - now - return (delta.seconds + (delta.days * 24 * 3600)) - - -if __name__ == "__main__": - import doctest - doctest.testmod() diff --git a/nova/compute/service.py b/nova/compute/service.py index 9bf498d03..4df7e7171 100644 --- a/nova/compute/service.py +++ b/nova/compute/service.py @@ -29,4 +29,3 @@ class ComputeService(service.Service): Compute Service automatically passes commands on to the Compute Manager """ pass - -- cgit From e5b93d09d7095316921cd457887a8b4d8808c3c5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 30 Aug 2010 21:21:31 -0700 Subject: add missing manager classes --- nova/compute/manager.py | 202 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 nova/compute/manager.py (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py new file mode 100644 index 000000000..59f56730b --- /dev/null +++ b/nova/compute/manager.py @@ -0,0 +1,202 @@ +# 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. + +""" +Compute Manager: + + Handles all code relating to instances + +""" + +import base64 +import logging +import os + +from twisted.internet import defer + +from nova import db +from nova import exception +from nova import flags +from nova import process +from nova import manager +from nova import utils +from nova.compute import power_state + + +FLAGS = flags.FLAGS +flags.DEFINE_string('instances_path', utils.abspath('../instances'), + 'where instances are stored on disk') +flags.DEFINE_string('compute_driver', 'nova.virt.connection.get_connection', + 'Driver to use for volume creation') + + +class ComputeManager(manager.Manager): + """ + Manages the running instances. + """ + def __init__(self, compute_driver=None, *args, **kwargs): + """Load configuration options and connect to the hypervisor.""" + # TODO(vish): sync driver creation logic with the rest of the system + if not compute_driver: + compute_driver = FLAGS.compute_driver + self.driver = utils.import_object(compute_driver) + self.network_manager = utils.import_object(FLAGS.network_manager) + super(ComputeManager, self).__init__(*args, **kwargs) + # TODO(joshua): This needs to ensure system state, specifically + # modprobe aoe + + def _update_state(self, context, instance_id): + """Update the state of an instance from the driver info""" + # FIXME(ja): include other fields from state? + instance_ref = db.instance_get(context, instance_id) + state = self.driver.get_info(instance_ref.name)['state'] + db.instance_state(context, instance_id, state) + + @defer.inlineCallbacks + @exception.wrap_exception + def run_instance(self, context, instance_id, **_kwargs): + """Launch a new instance with specified options.""" + instance_ref = db.instance_get(context, instance_id) + if instance_ref['str_id'] in self.driver.list_instances(): + raise exception.Error("Instance has already been created") + logging.debug("Starting instance %s...", instance_id) + project_id = instance_ref['project_id'] + self.network_manager.setup_compute_network(context, project_id) + db.instance_update(context, + instance_id, + {'node_name': FLAGS.node_name}) + + # TODO(vish) check to make sure the availability zone matches + db.instance_state(context, + instance_id, + power_state.NOSTATE, + 'spawning') + + try: + yield self.driver.spawn(instance_ref) + except: # pylint: disable-msg=W0702 + logging.exception("Failed to spawn instance %s", + instance_ref['name']) + db.instance_state(context, instance_id, power_state.SHUTDOWN) + + self._update_state(context, instance_id) + + @defer.inlineCallbacks + @exception.wrap_exception + def terminate_instance(self, context, instance_id): + """Terminate an instance on this machine.""" + logging.debug("Got told to terminate instance %s", instance_id) + instance_ref = db.instance_get(context, instance_id) + + if instance_ref['state'] == power_state.SHUTOFF: + # self.datamodel.destroy() FIXME: RE-ADD? + raise exception.Error('trying to destroy already destroyed' + ' instance: %s' % instance_id) + + db.instance_state( + context, instance_id, power_state.NOSTATE, 'shutting_down') + yield self.driver.destroy(instance_ref) + + # FIXME(ja): should we keep it in a terminated state for a bit? + db.instance_destroy(context, instance_id) + + @defer.inlineCallbacks + @exception.wrap_exception + def reboot_instance(self, context, instance_id): + """Reboot an instance on this server. + + KVM doesn't support reboot, so we terminate and restart. + + """ + self._update_state(context, instance_id) + instance_ref = db.instance_get(context, instance_id) + + # FIXME(ja): this is only checking the model state - not state on disk? + if instance_ref['state'] != power_state.RUNNING: + raise exception.Error( + 'trying to reboot a non-running' + 'instance: %s (state: %s excepted: %s)' % + (instance_ref['str_id'], + instance_ref['state'], + power_state.RUNNING)) + + logging.debug('rebooting instance %s', instance_ref['name']) + db.instance_state( + context, instance_id, power_state.NOSTATE, 'rebooting') + yield self.driver.reboot(instance_ref) + self._update_state(context, instance_id) + + @exception.wrap_exception + def get_console_output(self, context, instance_id): + """Send the console output for an instance.""" + # FIXME: Abstract this for Xen + + logging.debug("Getting console output for %s", (instance_id)) + instance_ref = db.instance_get(context, instance_id) + + if FLAGS.connection_type == 'libvirt': + fname = os.path.abspath(os.path.join(FLAGS.instances_path, + instance_ref['str_id'], + 'console.log')) + with open(fname, 'r') as f: + output = f.read() + else: + output = 'FAKE CONSOLE OUTPUT' + + # TODO(termie): this stuff belongs in the API layer, no need to + # munge the data we send to ourselves + output = {"InstanceId": instance_id, + "Timestamp": "2", + "output": base64.b64encode(output)} + return output + + @defer.inlineCallbacks + @exception.wrap_exception + def attach_volume(self, context, instance_id, volume_id, mountpoint): + """Attach a volume to an instance.""" + # TODO(termie): check that instance_id exists + volume_ref = db.volume_get(context, volume_id) + yield self._init_aoe() + yield process.simple_execute( + "sudo virsh attach-disk %s /dev/etherd/%s %s" % + (instance_id, + volume_ref['aoe_device'], + mountpoint.rpartition('/dev/')[2])) + db.volume_attached(context, volume_id, instance_id, mountpoint) + defer.returnValue(True) + + @defer.inlineCallbacks + @exception.wrap_exception + def detach_volume(self, context, instance_id, volume_id): + """Detach a volume from an instance.""" + # despite the documentation, virsh detach-disk just wants the device + # name without the leading /dev/ + # TODO(termie): check that instance_id exists + volume_ref = db.volume_get(context, volume_id) + target = volume_ref['mountpoint'].rpartition('/dev/')[2] + yield process.simple_execute( + "sudo virsh detach-disk %s %s " % (instance_id, target)) + db.volume_detached(context, volume_id) + defer.returnValue(True) + + @defer.inlineCallbacks + def _init_aoe(self): + """Discover aoe exported devices""" + # TODO(vish): these shell calls should move into a different layer. + yield process.simple_execute("sudo aoe-discover") + yield process.simple_execute("sudo aoe-stat") -- cgit From 8e3ab2119289cf082830aea39409a44cdff54e12 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 30 Aug 2010 22:21:47 -0700 Subject: a little more cleanup in compute --- nova/compute/manager.py | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 59f56730b..7723edd53 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -17,10 +17,7 @@ # under the License. """ -Compute Manager: - - Handles all code relating to instances - +Handles all code relating to instances (guest vms) """ import base64 @@ -57,8 +54,6 @@ class ComputeManager(manager.Manager): self.driver = utils.import_object(compute_driver) self.network_manager = utils.import_object(FLAGS.network_manager) super(ComputeManager, self).__init__(*args, **kwargs) - # TODO(joshua): This needs to ensure system state, specifically - # modprobe aoe def _update_state(self, context, instance_id): """Update the state of an instance from the driver info""" @@ -103,30 +98,28 @@ class ComputeManager(manager.Manager): logging.debug("Got told to terminate instance %s", instance_id) instance_ref = db.instance_get(context, instance_id) + # TODO(vish): move this logic to layer? if instance_ref['state'] == power_state.SHUTOFF: - # self.datamodel.destroy() FIXME: RE-ADD? + db.instance_destroy(context, instance_id) raise exception.Error('trying to destroy already destroyed' ' instance: %s' % instance_id) - db.instance_state( - context, instance_id, power_state.NOSTATE, 'shutting_down') + db.instance_state(context, + instance_id, + power_state.NOSTATE, + 'shutting_down') yield self.driver.destroy(instance_ref) - # FIXME(ja): should we keep it in a terminated state for a bit? + # TODO(ja): should we keep it in a terminated state for a bit? db.instance_destroy(context, instance_id) @defer.inlineCallbacks @exception.wrap_exception def reboot_instance(self, context, instance_id): - """Reboot an instance on this server. - - KVM doesn't support reboot, so we terminate and restart. - - """ + """Reboot an instance on this server.""" self._update_state(context, instance_id) instance_ref = db.instance_get(context, instance_id) - # FIXME(ja): this is only checking the model state - not state on disk? if instance_ref['state'] != power_state.RUNNING: raise exception.Error( 'trying to reboot a non-running' @@ -136,15 +129,17 @@ class ComputeManager(manager.Manager): power_state.RUNNING)) logging.debug('rebooting instance %s', instance_ref['name']) - db.instance_state( - context, instance_id, power_state.NOSTATE, 'rebooting') + db.instance_state(context, + instance_id, + power_state.NOSTATE, + 'rebooting') yield self.driver.reboot(instance_ref) self._update_state(context, instance_id) @exception.wrap_exception def get_console_output(self, context, instance_id): """Send the console output for an instance.""" - # FIXME: Abstract this for Xen + # TODO(vish): Move this into the driver layer logging.debug("Getting console output for %s", (instance_id)) instance_ref = db.instance_get(context, instance_id) @@ -172,6 +167,7 @@ class ComputeManager(manager.Manager): # TODO(termie): check that instance_id exists volume_ref = db.volume_get(context, volume_id) yield self._init_aoe() + # TODO(vish): Move this into the driver layer yield process.simple_execute( "sudo virsh attach-disk %s /dev/etherd/%s %s" % (instance_id, @@ -189,6 +185,7 @@ class ComputeManager(manager.Manager): # TODO(termie): check that instance_id exists volume_ref = db.volume_get(context, volume_id) target = volume_ref['mountpoint'].rpartition('/dev/')[2] + # TODO(vish): Move this into the driver layer yield process.simple_execute( "sudo virsh detach-disk %s %s " % (instance_id, target)) db.volume_detached(context, volume_id) @@ -197,6 +194,6 @@ class ComputeManager(manager.Manager): @defer.inlineCallbacks def _init_aoe(self): """Discover aoe exported devices""" - # TODO(vish): these shell calls should move into a different layer. + # TODO(vish): these shell calls should move into volume manager. yield process.simple_execute("sudo aoe-discover") yield process.simple_execute("sudo aoe-stat") -- cgit From 2c16344cfea8461e96425a2c375b4dabd21f03c5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 31 Aug 2010 16:48:41 -0700 Subject: rename node_name to host --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 7723edd53..c15c9e1f5 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -74,7 +74,7 @@ class ComputeManager(manager.Manager): self.network_manager.setup_compute_network(context, project_id) db.instance_update(context, instance_id, - {'node_name': FLAGS.node_name}) + {'host': FLAGS.host}) # TODO(vish) check to make sure the availability zone matches db.instance_state(context, -- cgit From 116402306e0d7703645e786b7cf0833a113b8d13 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 2 Sep 2010 11:25:10 -0700 Subject: updated models a bit and removed service classes --- nova/compute/service.py | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 nova/compute/service.py (limited to 'nova/compute') diff --git a/nova/compute/service.py b/nova/compute/service.py deleted file mode 100644 index 4df7e7171..000000000 --- a/nova/compute/service.py +++ /dev/null @@ -1,31 +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. - -""" -Compute service allows rpc calls to the compute manager and reports state -to the database. -""" - -from nova import service - - -class ComputeService(service.Service): - """ - Compute Service automatically passes commands on to the Compute Manager - """ - pass -- cgit From 9db707dda70bbb11d944ab357841c9bdd5ef5b07 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 7 Sep 2010 05:26:08 -0700 Subject: Lots of fixes to make the nova commands work properly and make datamodel work with mysql properly --- nova/compute/manager.py | 104 ++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 57 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index c15c9e1f5..13e5dcd1f 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -26,10 +26,8 @@ import os from twisted.internet import defer -from nova import db from nova import exception from nova import flags -from nova import process from nova import manager from nova import utils from nova.compute import power_state @@ -53,41 +51,42 @@ class ComputeManager(manager.Manager): compute_driver = FLAGS.compute_driver self.driver = utils.import_object(compute_driver) self.network_manager = utils.import_object(FLAGS.network_manager) + self.volume_manager = utils.import_object(FLAGS.volume_manager) super(ComputeManager, self).__init__(*args, **kwargs) def _update_state(self, context, instance_id): """Update the state of an instance from the driver info""" # FIXME(ja): include other fields from state? - instance_ref = db.instance_get(context, instance_id) + instance_ref = self.db.instance_get(context, instance_id) state = self.driver.get_info(instance_ref.name)['state'] - db.instance_state(context, instance_id, state) + self.db.instance_state(context, instance_id, state) @defer.inlineCallbacks @exception.wrap_exception def run_instance(self, context, instance_id, **_kwargs): """Launch a new instance with specified options.""" - instance_ref = db.instance_get(context, instance_id) + instance_ref = self.db.instance_get(context, instance_id) if instance_ref['str_id'] in self.driver.list_instances(): raise exception.Error("Instance has already been created") - logging.debug("Starting instance %s...", instance_id) + logging.debug("instance %s: starting...", instance_id) project_id = instance_ref['project_id'] self.network_manager.setup_compute_network(context, project_id) - db.instance_update(context, - instance_id, - {'host': FLAGS.host}) + self.db.instance_update(context, + instance_id, + {'host': self.host}) # TODO(vish) check to make sure the availability zone matches - db.instance_state(context, - instance_id, - power_state.NOSTATE, - 'spawning') + self.db.instance_state(context, + instance_id, + power_state.NOSTATE, + 'spawning') try: yield self.driver.spawn(instance_ref) except: # pylint: disable-msg=W0702 - logging.exception("Failed to spawn instance %s", + logging.exception("instance %s: Failed to spawn", instance_ref['name']) - db.instance_state(context, instance_id, power_state.SHUTDOWN) + self.db.instance_state(context, instance_id, power_state.SHUTDOWN) self._update_state(context, instance_id) @@ -95,30 +94,30 @@ class ComputeManager(manager.Manager): @exception.wrap_exception def terminate_instance(self, context, instance_id): """Terminate an instance on this machine.""" - logging.debug("Got told to terminate instance %s", instance_id) - instance_ref = db.instance_get(context, instance_id) + logging.debug("instance %s: terminating", instance_id) + instance_ref = self.db.instance_get(context, instance_id) # TODO(vish): move this logic to layer? if instance_ref['state'] == power_state.SHUTOFF: - db.instance_destroy(context, instance_id) + self.db.instance_destroy(context, instance_id) raise exception.Error('trying to destroy already destroyed' ' instance: %s' % instance_id) - db.instance_state(context, - instance_id, - power_state.NOSTATE, - 'shutting_down') + self.db.instance_state(context, + instance_id, + power_state.NOSTATE, + 'shutting_down') yield self.driver.destroy(instance_ref) # TODO(ja): should we keep it in a terminated state for a bit? - db.instance_destroy(context, instance_id) + self.db.instance_destroy(context, instance_id) @defer.inlineCallbacks @exception.wrap_exception def reboot_instance(self, context, instance_id): """Reboot an instance on this server.""" self._update_state(context, instance_id) - instance_ref = db.instance_get(context, instance_id) + instance_ref = self.db.instance_get(context, instance_id) if instance_ref['state'] != power_state.RUNNING: raise exception.Error( @@ -128,11 +127,11 @@ class ComputeManager(manager.Manager): instance_ref['state'], power_state.RUNNING)) - logging.debug('rebooting instance %s', instance_ref['name']) - db.instance_state(context, - instance_id, - power_state.NOSTATE, - 'rebooting') + logging.debug('instance %s: rebooting', instance_ref['name']) + self.db.instance_state(context, + instance_id, + power_state.NOSTATE, + 'rebooting') yield self.driver.reboot(instance_ref) self._update_state(context, instance_id) @@ -141,8 +140,8 @@ class ComputeManager(manager.Manager): """Send the console output for an instance.""" # TODO(vish): Move this into the driver layer - logging.debug("Getting console output for %s", (instance_id)) - instance_ref = db.instance_get(context, instance_id) + logging.debug("instance %s: getting console output", instance_id) + instance_ref = self.db.instance_get(context, instance_id) if FLAGS.connection_type == 'libvirt': fname = os.path.abspath(os.path.join(FLAGS.instances_path, @@ -164,36 +163,27 @@ class ComputeManager(manager.Manager): @exception.wrap_exception def attach_volume(self, context, instance_id, volume_id, mountpoint): """Attach a volume to an instance.""" - # TODO(termie): check that instance_id exists - volume_ref = db.volume_get(context, volume_id) - yield self._init_aoe() - # TODO(vish): Move this into the driver layer - yield process.simple_execute( - "sudo virsh attach-disk %s /dev/etherd/%s %s" % - (instance_id, - volume_ref['aoe_device'], - mountpoint.rpartition('/dev/')[2])) - db.volume_attached(context, volume_id, instance_id, mountpoint) + logging.debug("instance %s: attaching volume %s to %s", instance_id, + volume_id, mountpoint) + instance_ref = self.db.instance_get(context, instance_id) + dev_path = yield self.volume_manager.setup_compute_volume(context, + volume_id) + yield self.driver.attach_volume(instance_ref['str_id'], + dev_path, + mountpoint) + self.db.volume_attached(context, volume_id, instance_id, mountpoint) defer.returnValue(True) @defer.inlineCallbacks @exception.wrap_exception def detach_volume(self, context, instance_id, volume_id): """Detach a volume from an instance.""" - # despite the documentation, virsh detach-disk just wants the device - # name without the leading /dev/ - # TODO(termie): check that instance_id exists - volume_ref = db.volume_get(context, volume_id) - target = volume_ref['mountpoint'].rpartition('/dev/')[2] - # TODO(vish): Move this into the driver layer - yield process.simple_execute( - "sudo virsh detach-disk %s %s " % (instance_id, target)) - db.volume_detached(context, volume_id) + logging.debug("instance %s: detaching volume %s", + instance_id, + volume_id) + instance_ref = self.db.instance_get(context, instance_id) + volume_ref = self.db.volume_get(context, volume_id) + self.driver.detach_volume(instance_ref['str_id'], + volume_ref['mountpoint']) + self.db.volume_detached(context, volume_id) defer.returnValue(True) - - @defer.inlineCallbacks - def _init_aoe(self): - """Discover aoe exported devices""" - # TODO(vish): these shell calls should move into volume manager. - yield process.simple_execute("sudo aoe-discover") - yield process.simple_execute("sudo aoe-stat") -- cgit From 0f3317735edbaf76c3437c1fe5407b575927d202 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 7 Sep 2010 20:09:42 -0700 Subject: review cleanup for compute manager --- nova/compute/manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 13e5dcd1f..878205a36 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -83,7 +83,7 @@ class ComputeManager(manager.Manager): try: yield self.driver.spawn(instance_ref) - except: # pylint: disable-msg=W0702 + except Exception: # pylint: disable-msg=W0702 logging.exception("instance %s: Failed to spawn", instance_ref['name']) self.db.instance_state(context, instance_id, power_state.SHUTDOWN) @@ -97,7 +97,6 @@ class ComputeManager(manager.Manager): logging.debug("instance %s: terminating", instance_id) instance_ref = self.db.instance_get(context, instance_id) - # TODO(vish): move this logic to layer? if instance_ref['state'] == power_state.SHUTOFF: self.db.instance_destroy(context, instance_id) raise exception.Error('trying to destroy already destroyed' -- cgit From 607162ffe86d7d2b5bd9eb6f16a6ee4405892fc6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 8 Sep 2010 01:53:07 -0700 Subject: make timestamps for instances and volumes, includes additions to get deleted objects from db using deleted flag. --- nova/compute/manager.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 878205a36..7f6b49f90 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -21,6 +21,7 @@ Handles all code relating to instances (guest vms) """ import base64 +import datetime import logging import os @@ -83,6 +84,8 @@ class ComputeManager(manager.Manager): try: yield self.driver.spawn(instance_ref) + now = datetime.datetime.now() + self.db.instance_update(None, instance_id, {'launched_at': now}) except Exception: # pylint: disable-msg=W0702 logging.exception("instance %s: Failed to spawn", instance_ref['name']) @@ -107,6 +110,8 @@ class ComputeManager(manager.Manager): power_state.NOSTATE, 'shutting_down') yield self.driver.destroy(instance_ref) + now = datetime.datetime.now() + self.db.instance_update(None, instance_id, {'terminated_at': now}) # TODO(ja): should we keep it in a terminated state for a bit? self.db.instance_destroy(context, instance_id) -- cgit From 20656789e919f36733ac9fd0766a56a1c96d1e34 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 9 Sep 2010 02:35:11 -0700 Subject: set state everywhere --- nova/compute/manager.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 878205a36..5f7a94106 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -59,7 +59,7 @@ class ComputeManager(manager.Manager): # FIXME(ja): include other fields from state? instance_ref = self.db.instance_get(context, instance_id) state = self.driver.get_info(instance_ref.name)['state'] - self.db.instance_state(context, instance_id, state) + self.db.instance_set_state(context, instance_id, state) @defer.inlineCallbacks @exception.wrap_exception @@ -76,17 +76,19 @@ class ComputeManager(manager.Manager): {'host': self.host}) # TODO(vish) check to make sure the availability zone matches - self.db.instance_state(context, - instance_id, - power_state.NOSTATE, - 'spawning') + self.db.instance_set_state(context, + instance_id, + power_state.NOSTATE, + 'spawning') try: yield self.driver.spawn(instance_ref) except Exception: # pylint: disable-msg=W0702 logging.exception("instance %s: Failed to spawn", instance_ref['name']) - self.db.instance_state(context, instance_id, power_state.SHUTDOWN) + self.db.instance_set_state(context, + instance_id, + power_state.SHUTDOWN) self._update_state(context, instance_id) @@ -102,10 +104,10 @@ class ComputeManager(manager.Manager): raise exception.Error('trying to destroy already destroyed' ' instance: %s' % instance_id) - self.db.instance_state(context, - instance_id, - power_state.NOSTATE, - 'shutting_down') + self.db.instance_set_state(context, + instance_id, + power_state.NOSTATE, + 'shutting_down') yield self.driver.destroy(instance_ref) # TODO(ja): should we keep it in a terminated state for a bit? @@ -127,10 +129,10 @@ class ComputeManager(manager.Manager): power_state.RUNNING)) logging.debug('instance %s: rebooting', instance_ref['name']) - self.db.instance_state(context, - instance_id, - power_state.NOSTATE, - 'rebooting') + self.db.instance_set_state(context, + instance_id, + power_state.NOSTATE, + 'rebooting') yield self.driver.reboot(instance_ref) self._update_state(context, instance_id) -- cgit From b8aaebee171876ffd0e115ea3a19d4524ca16d99 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 9 Sep 2010 06:06:29 -0700 Subject: switch to using utcnow --- nova/compute/manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 4b29add2d..ae7099812 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -84,7 +84,7 @@ class ComputeManager(manager.Manager): try: yield self.driver.spawn(instance_ref) - now = datetime.datetime.now() + now = datetime.datetime.utcnow() self.db.instance_update(None, instance_id, {'launched_at': now}) except Exception: # pylint: disable-msg=W0702 logging.exception("instance %s: Failed to spawn", @@ -112,7 +112,7 @@ class ComputeManager(manager.Manager): power_state.NOSTATE, 'shutting_down') yield self.driver.destroy(instance_ref) - now = datetime.datetime.now() + now = datetime.datetime.utcnow() self.db.instance_update(None, instance_id, {'terminated_at': now}) # TODO(ja): should we keep it in a terminated state for a bit? -- cgit From c000a1f88141c7887943a96a8a7ced3b79d70f7e Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sat, 11 Sep 2010 08:43:48 -0700 Subject: added terminated_at to volume and moved setting of terminated_at into cloud --- nova/compute/manager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index ae7099812..954227b42 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -85,7 +85,9 @@ class ComputeManager(manager.Manager): try: yield self.driver.spawn(instance_ref) now = datetime.datetime.utcnow() - self.db.instance_update(None, instance_id, {'launched_at': now}) + self.db.instance_update(context, + instance_id, + {'launched_at': now}) except Exception: # pylint: disable-msg=W0702 logging.exception("instance %s: Failed to spawn", instance_ref['name']) @@ -100,8 +102,8 @@ class ComputeManager(manager.Manager): def terminate_instance(self, context, instance_id): """Terminate an instance on this machine.""" logging.debug("instance %s: terminating", instance_id) - instance_ref = self.db.instance_get(context, instance_id) + instance_ref = self.db.instance_get(context, instance_id) if instance_ref['state'] == power_state.SHUTOFF: self.db.instance_destroy(context, instance_id) raise exception.Error('trying to destroy already destroyed' @@ -112,8 +114,6 @@ class ComputeManager(manager.Manager): power_state.NOSTATE, 'shutting_down') yield self.driver.destroy(instance_ref) - now = datetime.datetime.utcnow() - self.db.instance_update(None, instance_id, {'terminated_at': now}) # TODO(ja): should we keep it in a terminated state for a bit? self.db.instance_destroy(context, instance_id) -- cgit From 2774466197a0dda3763569fe7aa1a578baf5e059 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 13 Sep 2010 02:15:02 -0700 Subject: added missing yield in detach_volume --- nova/compute/manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 954227b42..24538e4f1 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -189,7 +189,7 @@ class ComputeManager(manager.Manager): volume_id) instance_ref = self.db.instance_get(context, instance_id) volume_ref = self.db.volume_get(context, volume_id) - self.driver.detach_volume(instance_ref['str_id'], - volume_ref['mountpoint']) + yield self.driver.detach_volume(instance_ref['str_id'], + volume_ref['mountpoint']) self.db.volume_detached(context, volume_id) defer.returnValue(True) -- cgit From 077fc783c4f94de427da98818d262aeb09a31044 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 13 Sep 2010 12:04:06 +0200 Subject: (Untested) Make changes to security group rules propagate to the relevant compute nodes. --- nova/compute/manager.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 5f7a94106..a00fd9baa 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -61,6 +61,11 @@ class ComputeManager(manager.Manager): state = self.driver.get_info(instance_ref.name)['state'] self.db.instance_set_state(context, instance_id, state) + @defer.inlineCallbacks + @exception.wrap_exception + def refresh_security_group(self, context, security_group_id, **_kwargs): + self.driver.refresh_security_group(security_group_id) + @defer.inlineCallbacks @exception.wrap_exception def run_instance(self, context, instance_id, **_kwargs): -- cgit From 65113c4aa92fa5e803bbe1ab56f7facf57753962 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 14 Sep 2010 15:20:08 +0200 Subject: Make refresh_security_groups play well with inlineCallbacks. --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index a00fd9baa..1f3a181ff 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -64,7 +64,7 @@ class ComputeManager(manager.Manager): @defer.inlineCallbacks @exception.wrap_exception def refresh_security_group(self, context, security_group_id, **_kwargs): - self.driver.refresh_security_group(security_group_id) + yield self.driver.refresh_security_group(security_group_id) @defer.inlineCallbacks @exception.wrap_exception -- cgit From a3d003d7ec92f3ae23a667954a790c71efdbfdbe Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 20 Sep 2010 11:46:18 +0200 Subject: Move the code that extracts the console output into the virt drivers. Move the code that formats it up into the API layer. Add support for Xen console. --- nova/compute/manager.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index ae7099812..9f5674be2 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -144,26 +144,10 @@ class ComputeManager(manager.Manager): @exception.wrap_exception def get_console_output(self, context, instance_id): """Send the console output for an instance.""" - # TODO(vish): Move this into the driver layer - logging.debug("instance %s: getting console output", instance_id) instance_ref = self.db.instance_get(context, instance_id) - if FLAGS.connection_type == 'libvirt': - fname = os.path.abspath(os.path.join(FLAGS.instances_path, - instance_ref['str_id'], - 'console.log')) - with open(fname, 'r') as f: - output = f.read() - else: - output = 'FAKE CONSOLE OUTPUT' - - # TODO(termie): this stuff belongs in the API layer, no need to - # munge the data we send to ourselves - output = {"InstanceId": instance_id, - "Timestamp": "2", - "output": base64.b64encode(output)} - return output + return self.driver.get_console_output(instance_ref) @defer.inlineCallbacks @exception.wrap_exception -- cgit From 2327378a1e5c9fa942d56001919caaeb1be1c7cb Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Tue, 28 Sep 2010 18:38:19 -0700 Subject: Removed str_id from FixedIp references --- nova/compute/manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 24538e4f1..f370ede8b 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['str_id'] in self.driver.list_instances(): + if instance_ref['ec2_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['str_id'], + (instance_ref['ec2_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['str_id'], + instance_ref['ec2_id'], 'console.log')) with open(fname, 'r') as f: output = f.read() @@ -174,7 +174,7 @@ class ComputeManager(manager.Manager): instance_ref = self.db.instance_get(context, instance_id) dev_path = yield self.volume_manager.setup_compute_volume(context, volume_id) - yield self.driver.attach_volume(instance_ref['str_id'], + yield self.driver.attach_volume(instance_ref['ec2_id'], dev_path, mountpoint) self.db.volume_attached(context, volume_id, instance_id, mountpoint) @@ -189,7 +189,7 @@ class ComputeManager(manager.Manager): volume_id) instance_ref = self.db.instance_get(context, instance_id) volume_ref = self.db.volume_get(context, volume_id) - yield self.driver.detach_volume(instance_ref['str_id'], + yield self.driver.detach_volume(instance_ref['ec2_id'], volume_ref['mountpoint']) self.db.volume_detached(context, volume_id) defer.returnValue(True) -- cgit From 39080e5f5000e0f401ff19f3fd9dd8cfbffffe69 Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Thu, 30 Sep 2010 22:05:16 -0400 Subject: Find other places in the code that used ec2_id or get_instance_by_ec2_id and use internal_id as appropriate --- nova/compute/manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/compute') 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() -- cgit From 48ff601a3ab2d72275061135cac56557042e8e9d Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sat, 2 Oct 2010 12:46:12 -0700 Subject: fix typo in setup_compute_network --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index f370ede8b..4c6d2f06f 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -71,7 +71,7 @@ class ComputeManager(manager.Manager): raise exception.Error("Instance has already been created") logging.debug("instance %s: starting...", instance_id) project_id = instance_ref['project_id'] - self.network_manager.setup_compute_network(context, project_id) + self.network_manager.setup_compute_network(context, instance_id) self.db.instance_update(context, instance_id, {'host': self.host}) -- cgit From 32ea289d13a7ec9d273a57d2bf30484b80bfebec Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Tue, 12 Oct 2010 13:42:43 -0400 Subject: Now that the ec2 id is not the same as the name of the instance, don't compare internal_id [nee ec2_id] to instance names provided by the virtualization driver. Compare names directly instead. --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/compute') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 131fac406..99705d3a9 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['internal_id'] in self.driver.list_instances(): + if instance_ref['name'] 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'] -- cgit