~ubuntu-branches/ubuntu/quantal/nova/quantal-proposed

« back to all changes in this revision

Viewing changes to nova/scheduler/filter_scheduler.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-08-16 14:04:11 UTC
  • mto: This revision was merged to the branch mainline in revision 84.
  • Revision ID: package-import@ubuntu.com-20120816140411-0mr4n241wmk30t9l
Tags: upstream-2012.2~f3
ImportĀ upstreamĀ versionĀ 2012.2~f3

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
from nova import exception
25
25
from nova import flags
26
 
from nova.notifier import api as notifier
27
26
from nova.openstack.common import importutils
28
27
from nova.openstack.common import log as logging
 
28
from nova.openstack.common.notifier import api as notifier
29
29
from nova.scheduler import driver
30
30
from nova.scheduler import least_cost
31
31
from nova.scheduler import scheduler_options
51
51
        msg = _("No host selection for %s defined.") % topic
52
52
        raise exception.NoValidHost(reason=msg)
53
53
 
54
 
    def schedule_run_instance(self, context, request_spec, reservations,
55
 
                              *args, **kwargs):
 
54
    def schedule_run_instance(self, context, request_spec,
 
55
                              admin_password, injected_files,
 
56
                              requested_networks, is_first_time,
 
57
                              filter_properties, reservations):
56
58
        """This method is called from nova.compute.api to provision
57
59
        an instance.  We first create a build plan (a list of WeightedHosts)
58
60
        and then provision.
59
61
 
60
62
        Returns a list of the instances created.
61
63
        """
62
 
 
63
64
        elevated = context.elevated()
64
65
        num_instances = request_spec.get('num_instances', 1)
65
66
        LOG.debug(_("Attempting to build %(num_instances)d instance(s)") %
70
71
                        'scheduler.run_instance.start', notifier.INFO, payload)
71
72
 
72
73
        weighted_hosts = self._schedule(context, "compute", request_spec,
73
 
                                        *args, **kwargs)
 
74
                                        filter_properties)
74
75
 
75
76
        if not weighted_hosts:
76
77
            raise exception.NoValidHost(reason="")
77
78
 
78
79
        # NOTE(comstud): Make sure we do not pass this through.  It
79
80
        # contains an instance of RpcContext that cannot be serialized.
80
 
        kwargs.pop('filter_properties', None)
 
81
        filter_properties.pop('context', None)
81
82
 
82
83
        instances = []
83
84
        for num in xrange(num_instances):
86
87
            weighted_host = weighted_hosts.pop(0)
87
88
 
88
89
            request_spec['instance_properties']['launch_index'] = num
 
90
 
89
91
            instance = self._provision_resource(elevated, weighted_host,
90
92
                                                request_spec, reservations,
91
 
                                                kwargs)
 
93
                                                filter_properties,
 
94
                                                requested_networks,
 
95
                                                injected_files, admin_password,
 
96
                                                is_first_time)
 
97
            # scrub retry host list in case we're scheduling multiple
 
98
            # instances:
 
99
            retry = filter_properties.get('retry', {})
 
100
            retry['hosts'] = []
92
101
 
93
102
            if instance:
94
103
                instances.append(instance)
98
107
 
99
108
        return instances
100
109
 
101
 
    def schedule_prep_resize(self, context, request_spec, *args, **kwargs):
 
110
    def schedule_prep_resize(self, context, image, request_spec,
 
111
                             filter_properties, instance, instance_type,
 
112
                             reservations=None):
102
113
        """Select a target for resize.
103
114
 
104
115
        Selects a target host for the instance, post-resize, and casts
106
117
        """
107
118
 
108
119
        hosts = self._schedule(context, 'compute', request_spec,
109
 
                               *args, **kwargs)
 
120
                               filter_properties)
110
121
        if not hosts:
111
122
            raise exception.NoValidHost(reason="")
112
123
        host = hosts.pop(0)
113
124
 
114
 
        # NOTE(comstud): Make sure we do not pass this through.  It
115
 
        # contains an instance of RpcContext that cannot be serialized.
116
 
        kwargs.pop('filter_properties', None)
117
 
 
118
125
        # Forward off to the host
119
 
        driver.cast_to_compute_host(context, host.host_state.host,
120
 
                'prep_resize', **kwargs)
 
126
        self.compute_rpcapi.prep_resize(context, image, instance,
 
127
                instance_type, host.host_state.host, reservations)
121
128
 
122
129
    def _provision_resource(self, context, weighted_host, request_spec,
123
 
            reservations, kwargs):
 
130
            reservations, filter_properties, requested_networks,
 
131
            injected_files, admin_password, is_first_time):
124
132
        """Create the requested resource in this Zone."""
125
133
        instance = self.create_instance_db_entry(context, request_spec,
126
134
                                                 reservations)
127
135
 
 
136
        # Add a retry entry for the selected compute host:
 
137
        self._add_retry_host(filter_properties, weighted_host.host_state.host)
 
138
 
128
139
        payload = dict(request_spec=request_spec,
129
140
                       weighted_host=weighted_host.to_dict(),
130
141
                       instance_id=instance['uuid'])
132
143
                        'scheduler.run_instance.scheduled', notifier.INFO,
133
144
                        payload)
134
145
 
135
 
        driver.cast_to_compute_host(context, weighted_host.host_state.host,
136
 
                'run_instance', instance_uuid=instance['uuid'], **kwargs)
137
 
        inst = driver.encode_instance(instance, local=True)
 
146
        updated_instance = driver.instance_update_db(context, instance['uuid'],
 
147
                weighted_host.host_state.host)
 
148
 
 
149
        self.compute_rpcapi.run_instance(context, instance=updated_instance,
 
150
                host=weighted_host.host_state.host,
 
151
                request_spec=request_spec, filter_properties=filter_properties,
 
152
                requested_networks=requested_networks,
 
153
                injected_files=injected_files,
 
154
                admin_password=admin_password, is_first_time=is_first_time)
 
155
 
 
156
        inst = driver.encode_instance(updated_instance, local=True)
 
157
 
138
158
        # So if another instance is created, create_instance_db_entry will
139
159
        # actually create a new entry, instead of assume it's been created
140
160
        # already
141
161
        del request_spec['instance_properties']['uuid']
 
162
 
142
163
        return inst
143
164
 
 
165
    def _add_retry_host(self, filter_properties, host):
 
166
        """Add a retry entry for the selected computep host.  In the event that
 
167
        the request gets re-scheduled, this entry will signal that the given
 
168
        host has already been tried.
 
169
        """
 
170
        retry = filter_properties.get('retry', None)
 
171
        if not retry:
 
172
            return
 
173
        hosts = retry['hosts']
 
174
        hosts.append(host)
 
175
 
144
176
    def _get_configuration_options(self):
145
177
        """Fetch options dictionary. Broken out for testing."""
146
178
        return self.options.get_configuration()
147
179
 
148
180
    def populate_filter_properties(self, request_spec, filter_properties):
149
 
        """Stuff things into filter_properties.  Can be overriden in a
 
181
        """Stuff things into filter_properties.  Can be overridden in a
150
182
        subclass to add more data.
151
183
        """
152
184
        pass
153
185
 
154
 
    def _schedule(self, context, topic, request_spec, *args, **kwargs):
 
186
    def _max_attempts(self):
 
187
        max_attempts = FLAGS.scheduler_max_attempts
 
188
        if max_attempts < 1:
 
189
            raise exception.NovaException(_("Invalid value for "
 
190
                "'scheduler_max_attempts', must be >= 1"))
 
191
        return max_attempts
 
192
 
 
193
    def _populate_retry(self, filter_properties, instance_properties):
 
194
        """Populate filter properties with history of retries for this
 
195
        request. If maximum retries is exceeded, raise NoValidHost.
 
196
        """
 
197
        max_attempts = self._max_attempts()
 
198
        retry = filter_properties.pop('retry', {})
 
199
 
 
200
        if max_attempts == 1:
 
201
            # re-scheduling is disabled.
 
202
            return
 
203
 
 
204
        # retry is enabled, update attempt count:
 
205
        if retry:
 
206
            retry['num_attempts'] += 1
 
207
        else:
 
208
            retry = {
 
209
                'num_attempts': 1,
 
210
                'hosts': []  # list of compute hosts tried
 
211
            }
 
212
        filter_properties['retry'] = retry
 
213
 
 
214
        if retry['num_attempts'] > max_attempts:
 
215
            uuid = instance_properties.get('uuid', None)
 
216
            msg = _("Exceeded max scheduling attempts %d ") % max_attempts
 
217
            raise exception.NoValidHost(msg, instance_uuid=uuid)
 
218
 
 
219
    def _schedule(self, context, topic, request_spec, filter_properties):
155
220
        """Returns a list of hosts that meet the required specs,
156
221
        ordered by their fitness.
157
222
        """
166
231
        cost_functions = self.get_cost_functions()
167
232
        config_options = self._get_configuration_options()
168
233
 
169
 
        filter_properties = kwargs.get('filter_properties', {})
 
234
        # check retry policy:
 
235
        self._populate_retry(filter_properties, instance_properties)
 
236
 
170
237
        filter_properties.update({'context': context,
171
238
                                  'request_spec': request_spec,
172
239
                                  'config_options': config_options,