1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright (c) 2010 OpenStack, LLC.
4
# Copyright 2010 United States Government as represented by the
5
# Administrator of the National Aeronautics and Space Administration.
8
# Licensed under the Apache License, Version 2.0 (the "License"); you may
9
# not use this file except in compliance with the License. You may obtain
10
# a copy of the License at
12
# http://www.apache.org/licenses/LICENSE-2.0
14
# Unless required by applicable law or agreed to in writing, software
15
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17
# License for the specific language governing permissions and limitations
27
from cinder import exception
28
from cinder import flags
29
from cinder import log as logging
30
from cinder import manager
31
from cinder.notifier import api as notifier
32
from cinder.openstack.common import cfg
33
from cinder.openstack.common import importutils
34
from cinder import utils
37
LOG = logging.getLogger(__name__)
39
scheduler_driver_opt = cfg.StrOpt('scheduler_driver',
40
default='cinder.scheduler.simple.SimpleScheduler',
41
help='Default driver to use for the scheduler')
44
FLAGS.register_opt(scheduler_driver_opt)
47
class SchedulerManager(manager.Manager):
48
"""Chooses a host to run instances on."""
50
def __init__(self, scheduler_driver=None, *args, **kwargs):
51
if not scheduler_driver:
52
scheduler_driver = FLAGS.scheduler_driver
53
self.driver = importutils.import_object(scheduler_driver)
54
super(SchedulerManager, self).__init__(*args, **kwargs)
56
def __getattr__(self, key):
57
"""Converts all method calls to use the schedule method"""
58
return functools.partial(self._schedule, key)
60
def get_host_list(self, context):
61
"""Get a list of hosts from the HostManager."""
62
return self.driver.get_host_list()
64
def get_service_capabilities(self, context):
65
"""Get the normalized set of capabilities for this zone."""
66
return self.driver.get_service_capabilities()
68
def update_service_capabilities(self, context, service_name=None,
69
host=None, capabilities=None, **kwargs):
70
"""Process a capability update from a service node."""
71
if capabilities is None:
73
self.driver.update_service_capabilities(service_name, host,
76
def _schedule(self, method, context, topic, *args, **kwargs):
77
"""Tries to call schedule_* method on the driver to retrieve host.
78
Falls back to schedule(context, topic) if method doesn't exist.
80
driver_method_name = 'schedule_%s' % method
82
driver_method = getattr(self.driver, driver_method_name)
83
args = (context,) + args
84
except AttributeError, e:
85
LOG.warning(_("Driver Method %(driver_method_name)s missing: "
86
"%(e)s. Reverting to schedule()") % locals())
87
driver_method = self.driver.schedule
88
args = (context, topic, method) + args
90
# Scheduler methods are responsible for casting.
92
return driver_method(*args, **kwargs)
93
except Exception as ex:
94
with utils.save_and_reraise_exception():
95
self._set_vm_state_and_notify(method,
96
{'vm_state': vm_states.ERROR},
97
context, ex, *args, **kwargs)
99
def run_instance(self, context, topic, *args, **kwargs):
100
"""Tries to call schedule_run_instance on the driver.
101
Sets instance vm_state to ERROR on exceptions
103
args = (context,) + args
105
return self.driver.schedule_run_instance(*args, **kwargs)
106
except exception.NoValidHost as ex:
108
self._set_vm_state_and_notify('run_instance',
109
{'vm_state': vm_states.ERROR},
110
context, ex, *args, **kwargs)
111
except Exception as ex:
112
with utils.save_and_reraise_exception():
113
self._set_vm_state_and_notify('run_instance',
114
{'vm_state': vm_states.ERROR},
115
context, ex, *args, **kwargs)
117
def prep_resize(self, context, topic, *args, **kwargs):
118
"""Tries to call schedule_prep_resize on the driver.
119
Sets instance vm_state to ACTIVE on NoHostFound
120
Sets vm_state to ERROR on other exceptions
122
args = (context,) + args
124
return self.driver.schedule_prep_resize(*args, **kwargs)
125
except exception.NoValidHost as ex:
126
self._set_vm_state_and_notify('prep_resize',
127
{'vm_state': vm_states.ACTIVE,
129
context, ex, *args, **kwargs)
130
except Exception as ex:
131
with utils.save_and_reraise_exception():
132
self._set_vm_state_and_notify('prep_resize',
133
{'vm_state': vm_states.ERROR},
134
context, ex, *args, **kwargs)
136
def _set_vm_state_and_notify(self, method, updates, context, ex,
138
"""changes VM state and notifies"""
139
# FIXME(comstud): Re-factor this somehow. Not sure this belongs in the
140
# scheduler manager like this. We should make this easier.
141
# run_instance only sends a request_spec, and an instance may or may
142
# not have been created in the API (or scheduler) already. If it was
143
# created, there's a 'uuid' set in the instance_properties of the
145
# (littleidea): I refactored this a bit, and I agree
146
# it should be easier :)
147
# The refactoring could go further but trying to minimize changes
148
# for essex timeframe
150
LOG.warning(_("Failed to schedule_%(method)s: %(ex)s") % locals())
152
vm_state = updates['vm_state']
153
request_spec = kwargs.get('request_spec', {})
154
properties = request_spec.get('instance_properties', {})
155
instance_uuid = properties.get('uuid', {})
158
state = vm_state.upper()
159
LOG.warning(_('Setting instance to %(state)s state.'), locals(),
160
instance_uuid=instance_uuid)
161
db.instance_update(context, instance_uuid, updates)
163
payload = dict(request_spec=request_spec,
164
instance_properties=properties,
165
instance_id=instance_uuid,
170
notifier.notify(notifier.publisher_id("scheduler"),
171
'scheduler.' + method, notifier.ERROR, payload)
173
# NOTE (masumotok) : This method should be moved to cinder.api.ec2.admin.
174
# Based on bexar design summit discussion,
175
# just put this here for bexar release.
176
def show_host_resources(self, context, host):
177
"""Shows the physical/usage resource given by hosts.
179
:param context: security context
180
:param host: hostname
182
example format is below::
184
{'resource':D, 'usage':{proj_id1:D, proj_id2:D}}
185
D: {'vcpus': 3, 'memory_mb': 2048, 'local_gb': 2048,
186
'vcpus_used': 12, 'memory_mb_used': 10240,
190
# Getting compute node info and related instances info
191
compute_ref = db.service_get_all_compute_by_host(context, host)
192
compute_ref = compute_ref[0]
194
# Getting total available/used resource
195
compute_ref = compute_ref['compute_node'][0]
196
resource = {'vcpus': compute_ref['vcpus'],
197
'memory_mb': compute_ref['memory_mb'],
198
'local_gb': compute_ref['local_gb'],
199
'vcpus_used': compute_ref['vcpus_used'],
200
'memory_mb_used': compute_ref['memory_mb_used'],
201
'local_gb_used': compute_ref['local_gb_used']}
204
return {'resource': resource, 'usage': usage}