~nova-coresec/nova/bexar-translations

« back to all changes in this revision

Viewing changes to nova/compute/service.py

  • Committer: andy
  • Date: 2010-08-19 10:28:45 UTC
  • mto: (237.1.26 nova)
  • mto: This revision was merged to the branch mainline in revision 275.
  • Revision ID: github@anarkystic.com-20100819102845-il3al3v4ibclvgjf
Data abstraction for compute service

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
 
31
31
from twisted.internet import defer
32
32
 
 
33
from nova import db
33
34
from nova import exception
34
35
from nova import flags
35
36
from nova import process
44
45
 
45
46
FLAGS = flags.FLAGS
46
47
flags.DEFINE_string('instances_path', utils.abspath('../instances'),
47
 
                        'where instances are stored on disk')
 
48
                    'where instances are stored on disk')
48
49
 
49
50
 
50
51
class ComputeService(service.Service):
52
53
    Manages the running instances.
53
54
    """
54
55
    def __init__(self):
55
 
        """ load configuration options for this node and connect to the hypervisor"""
 
56
        """Load configuration options and connect to the hypervisor."""
56
57
        super(ComputeService, self).__init__()
57
58
        self._instances = {}
58
59
        self._conn = virt_connection.get_connection()
59
 
        # TODO(joshua): This needs to ensure system state, specifically: modprobe aoe
 
60
        # TODO(joshua): This needs to ensure system state, specifically
 
61
        #               modprobe aoe
60
62
 
61
63
    def noop(self):
62
 
        """ simple test of an AMQP message call """
 
64
        """Simple test of an AMQP message call."""
63
65
        return defer.succeed('PONG')
64
66
 
65
 
    def update_state(self, instance_id):
66
 
        inst = models.Instance.find(instance_id)
 
67
    def update_state(self, instance_id, context):
67
68
        # FIXME(ja): include other fields from state?
68
 
        inst.state = self._conn.get_info(inst.name)['state']
69
 
        inst.save()
70
 
 
71
 
    @exception.wrap_exception
72
 
    def adopt_instances(self):
73
 
        """ if there are instances already running, adopt them """
74
 
        return defer.succeed(0)
75
 
        instance_names = self._conn.list_instances()
76
 
        for name in instance_names:
77
 
            try:
78
 
                new_inst = Instance.fromName(self._conn, name)
79
 
                new_inst.update_state()
80
 
            except:
81
 
                pass
82
 
        return defer.succeed(len(self._instances))
 
69
        instance_ref = db.instance_get(context, instance_id)
 
70
        state = self._conn.get_info(instance_ref.name)['state']
 
71
        db.instance_state(context, instance_id, state)
83
72
 
84
73
    @defer.inlineCallbacks
85
74
    @exception.wrap_exception
86
 
    def run_instance(self, instance_id, **_kwargs):
87
 
        """ launch a new instance with specified options """
88
 
        inst = models.Instance.find(instance_id)
89
 
        if inst.name in self._conn.list_instances():
 
75
    def run_instance(self, instance_id, context=None, **_kwargs):
 
76
        """Launch a new instance with specified options."""
 
77
        instance_ref = db.instance_get(context, instance_id)
 
78
        if instance_ref['name'] in self._conn.list_instances():
90
79
            raise exception.Error("Instance has already been created")
91
80
        logging.debug("Starting instance %s..." % (instance_id))
92
 
        inst = models.Instance.find(instance_id)
 
81
 
93
82
        # NOTE(vish): passing network type allows us to express the
94
83
        #             network without making a call to network to find
95
84
        #             out which type of network to setup
96
 
        network_service.setup_compute_network(inst.project_id)
97
 
        inst.node_name = FLAGS.node_name
98
 
        inst.save()
 
85
        network_service.setup_compute_network(instance_ref['project_id'])
 
86
        db.instance_update(context, instance_id, {'node_name': FLAGS.node_name})
99
87
 
100
88
        # TODO(vish) check to make sure the availability zone matches
101
 
        inst.set_state(power_state.NOSTATE, 'spawning')
 
89
        db.instance_state(context, instance_id, power_state.NOSTATE, 'spawning')
102
90
 
103
91
        try:
104
 
            yield self._conn.spawn(inst)
 
92
            yield self._conn.spawn(instance_ref)
105
93
        except:
106
 
            logging.exception("Failed to spawn instance %s" % inst.name)
107
 
            inst.set_state(power_state.SHUTDOWN)
 
94
            logging.exception("Failed to spawn instance %s" %
 
95
                              instance_ref['name'])
 
96
            db.instance_state(context, instance_id, power_state.SHUTDOWN)
108
97
 
109
 
        self.update_state(instance_id)
 
98
        self.update_state(instance_id, context)
110
99
 
111
100
    @defer.inlineCallbacks
112
101
    @exception.wrap_exception
113
 
    def terminate_instance(self, instance_id):
114
 
        """ terminate an instance on this machine """
 
102
    def terminate_instance(self, instance_id, context=None):
 
103
        """Terminate an instance on this machine."""
115
104
        logging.debug("Got told to terminate instance %s" % instance_id)
116
 
        inst = models.Instance.find(instance_id)
 
105
        instance_ref = db.instance_get(context, instance_id)
117
106
 
118
 
        if inst.state == power_state.SHUTOFF:
119
 
            # self.datamodel.destroy() FIXME: RE-ADD ?????
 
107
        if instance_ref['state'] == power_state.SHUTOFF:
 
108
            # self.datamodel.destroy() FIXME: RE-ADD?
120
109
            raise exception.Error('trying to destroy already destroyed'
121
110
                                  ' instance: %s' % instance_id)
122
111
 
123
 
        inst.set_state(power_state.NOSTATE, 'shutting_down')
124
 
        yield self._conn.destroy(inst)
 
112
        db.instance_state(
 
113
                context, instance_id, power_state.NOSTATE, 'shutting_down')
 
114
        yield self._conn.destroy(instance_ref)
 
115
 
125
116
        # FIXME(ja): should we keep it in a terminated state for a bit?
126
 
        inst.delete()
 
117
        db.instance_destroy(context, instance_id)
127
118
 
128
119
    @defer.inlineCallbacks
129
120
    @exception.wrap_exception
130
 
    def reboot_instance(self, instance_id):
131
 
        """ reboot an instance on this server
132
 
        KVM doesn't support reboot, so we terminate and restart """
133
 
        self.update_state(instance_id)
134
 
        instance = models.Instance.find(instance_id)
 
121
    def reboot_instance(self, instance_id, context=None):
 
122
        """Reboot an instance on this server.
 
123
 
 
124
        KVM doesn't support reboot, so we terminate and restart.
 
125
        
 
126
        """
 
127
        self.update_state(instance_id, context)
 
128
        instance_ref = db.instance_get(context, instance_id)
135
129
 
136
130
        # FIXME(ja): this is only checking the model state - not state on disk?
137
 
        if instance.state != power_state.RUNNING:
 
131
        if instance_ref['state'] != power_state.RUNNING:
138
132
            raise exception.Error(
139
133
                    'trying to reboot a non-running'
140
 
                    'instance: %s (state: %s excepted: %s)' % (instance.name, instance.state, power_state.RUNNING))
 
134
                    'instance: %s (state: %s excepted: %s)' %
 
135
                    (instance_ref['name'],
 
136
                     instance_ref['state'],
 
137
                     power_state.RUNNING))
141
138
 
142
 
        logging.debug('rebooting instance %s' % instance.name)
143
 
        instance.set_state(power_state.NOSTATE, 'rebooting')
144
 
        yield self._conn.reboot(instance)
145
 
        self.update_state(instance_id)
 
139
        logging.debug('rebooting instance %s' % instance_ref['name'])
 
140
        db.instance_state(
 
141
                context, instance_id, power_state.NOSTATE, 'rebooting')
 
142
        yield self._conn.reboot(instance_ref)
 
143
        self.update_state(instance_id, context)
146
144
 
147
145
    @exception.wrap_exception
148
 
    def get_console_output(self, instance_id):
149
 
        """ send the console output for an instance """
 
146
    def get_console_output(self, instance_id, context=None):
 
147
        """Send the console output for an instance."""
150
148
        # FIXME: Abstract this for Xen
151
149
 
152
150
        logging.debug("Getting console output for %s" % (instance_id))
153
 
        inst = models.Instance.find(instance_id)
 
151
        instance_ref = db.instance_get(context, instance_id)
154
152
 
155
153
        if FLAGS.connection_type == 'libvirt':
156
 
            fname = os.path.abspath(
157
 
                    os.path.join(FLAGS.instances_path, inst.name, 'console.log'))
 
154
            fname = os.path.abspath(os.path.join(FLAGS.instances_path,
 
155
                                                 instance_ref['name'],
 
156
                                                 'console.log'))
158
157
            with open(fname, 'r') as f:
159
158
                output = f.read()
160
159
        else:
169
168
 
170
169
    @defer.inlineCallbacks
171
170
    @exception.wrap_exception
172
 
    def attach_volume(self, instance_id = None,
173
 
                      volume_id = None, mountpoint = None):
174
 
        volume = volume_service.get_volume(volume_id)
 
171
    def attach_volume(self, instance_id=None, volume_id=None, mountpoint=None,
 
172
                      context=None):
 
173
        """Attach a volume to an instance."""
 
174
        # TODO(termie): check that instance_id exists
 
175
        volume_ref = volume_get(context, volume_id)
175
176
        yield self._init_aoe()
176
177
        yield process.simple_execute(
177
178
                "sudo virsh attach-disk %s /dev/etherd/%s %s" %
178
179
                (instance_id,
179
180
                 volume['aoe_device'],
180
181
                 mountpoint.rpartition('/dev/')[2]))
181
 
        volume.finish_attach()
 
182
        volume_attached(context, volume_id)
182
183
        defer.returnValue(True)
183
184
 
184
185
    @defer.inlineCallbacks
185
 
    def _init_aoe(self):
186
 
        yield process.simple_execute("sudo aoe-discover")
187
 
        yield process.simple_execute("sudo aoe-stat")
188
 
 
189
 
    @defer.inlineCallbacks
190
186
    @exception.wrap_exception
191
 
    def detach_volume(self, instance_id, volume_id):
192
 
        """ detach a volume from an instance """
 
187
    def detach_volume(self, instance_id, volume_id, context=None):
 
188
        """Detach a volume from an instance."""
193
189
        # despite the documentation, virsh detach-disk just wants the device
194
190
        # name without the leading /dev/
195
 
        volume = volume_service.get_volume(volume_id)
 
191
        # TODO(termie): check that instance_id exists
 
192
        volume_ref = volume_get(context, volume_id)
196
193
        target = volume['mountpoint'].rpartition('/dev/')[2]
197
194
        yield process.simple_execute(
198
195
                "sudo virsh detach-disk %s %s " % (instance_id, target))
199
 
        volume.finish_detach()
 
196
        volume_detached(context, volume_id)
200
197
        defer.returnValue(True)
 
198
 
 
199
    @defer.inlineCallbacks
 
200
    def _init_aoe(self):
 
201
        yield process.simple_execute("sudo aoe-discover")
 
202
        yield process.simple_execute("sudo aoe-stat")