~ubuntu-branches/ubuntu/trusty/cinder/trusty

« back to all changes in this revision

Viewing changes to cinder/scheduler/manager.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-22 09:57:46 UTC
  • Revision ID: package-import@ubuntu.com-20120522095746-9lm71yvzltjybk4b
Tags: upstream-2012.2~f1~20120503.2
ImportĀ upstreamĀ versionĀ 2012.2~f1~20120503.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
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.
 
6
# All Rights Reserved.
 
7
#
 
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
 
11
#
 
12
#         http://www.apache.org/licenses/LICENSE-2.0
 
13
#
 
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
 
18
#    under the License.
 
19
 
 
20
"""
 
21
Scheduler Service
 
22
"""
 
23
 
 
24
import functools
 
25
 
 
26
from cinder import db
 
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
 
35
 
 
36
 
 
37
LOG = logging.getLogger(__name__)
 
38
 
 
39
scheduler_driver_opt = cfg.StrOpt('scheduler_driver',
 
40
        default='cinder.scheduler.simple.SimpleScheduler',
 
41
        help='Default driver to use for the scheduler')
 
42
 
 
43
FLAGS = flags.FLAGS
 
44
FLAGS.register_opt(scheduler_driver_opt)
 
45
 
 
46
 
 
47
class SchedulerManager(manager.Manager):
 
48
    """Chooses a host to run instances on."""
 
49
 
 
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)
 
55
 
 
56
    def __getattr__(self, key):
 
57
        """Converts all method calls to use the schedule method"""
 
58
        return functools.partial(self._schedule, key)
 
59
 
 
60
    def get_host_list(self, context):
 
61
        """Get a list of hosts from the HostManager."""
 
62
        return self.driver.get_host_list()
 
63
 
 
64
    def get_service_capabilities(self, context):
 
65
        """Get the normalized set of capabilities for this zone."""
 
66
        return self.driver.get_service_capabilities()
 
67
 
 
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:
 
72
            capabilities = {}
 
73
        self.driver.update_service_capabilities(service_name, host,
 
74
                capabilities)
 
75
 
 
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.
 
79
        """
 
80
        driver_method_name = 'schedule_%s' % method
 
81
        try:
 
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
 
89
 
 
90
        # Scheduler methods are responsible for casting.
 
91
        try:
 
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)
 
98
 
 
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
 
102
        """
 
103
        args = (context,) + args
 
104
        try:
 
105
            return self.driver.schedule_run_instance(*args, **kwargs)
 
106
        except exception.NoValidHost as ex:
 
107
            # don't reraise
 
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)
 
116
 
 
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
 
121
        """
 
122
        args = (context,) + args
 
123
        try:
 
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,
 
128
                                          'task_state': None},
 
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)
 
135
 
 
136
    def _set_vm_state_and_notify(self, method, updates, context, ex,
 
137
                                *args, **kwargs):
 
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
 
144
        # request_spec.
 
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
 
149
 
 
150
        LOG.warning(_("Failed to schedule_%(method)s: %(ex)s") % locals())
 
151
 
 
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', {})
 
156
 
 
157
        if instance_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)
 
162
 
 
163
        payload = dict(request_spec=request_spec,
 
164
                       instance_properties=properties,
 
165
                       instance_id=instance_uuid,
 
166
                       state=vm_state,
 
167
                       method=method,
 
168
                       reason=ex)
 
169
 
 
170
        notifier.notify(notifier.publisher_id("scheduler"),
 
171
                        'scheduler.' + method, notifier.ERROR, payload)
 
172
 
 
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.
 
178
 
 
179
        :param context: security context
 
180
        :param host: hostname
 
181
        :returns:
 
182
            example format is below::
 
183
 
 
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,
 
187
                    'local_gb_used': 64}
 
188
 
 
189
        """
 
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]
 
193
 
 
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']}
 
202
        usage = dict()
 
203
 
 
204
        return {'resource': resource, 'usage': usage}