51
51
msg = _("No host selection for %s defined.") % topic
52
52
raise exception.NoValidHost(reason=msg)
54
def schedule_run_instance(self, context, request_spec, reservations,
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.
60
62
Returns a list of the instances created.
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)
72
73
weighted_hosts = self._schedule(context, "compute", request_spec,
75
76
if not weighted_hosts:
76
77
raise exception.NoValidHost(reason="")
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)
83
84
for num in xrange(num_instances):
86
87
weighted_host = weighted_hosts.pop(0)
88
89
request_spec['instance_properties']['launch_index'] = num
89
91
instance = self._provision_resource(elevated, weighted_host,
90
92
request_spec, reservations,
95
injected_files, admin_password,
97
# scrub retry host list in case we're scheduling multiple
99
retry = filter_properties.get('retry', {})
94
103
instances.append(instance)
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,
102
113
"""Select a target for resize.
104
115
Selects a target host for the instance, post-resize, and casts
108
119
hosts = self._schedule(context, 'compute', request_spec,
111
122
raise exception.NoValidHost(reason="")
112
123
host = hosts.pop(0)
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)
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)
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,
136
# Add a retry entry for the selected compute host:
137
self._add_retry_host(filter_properties, weighted_host.host_state.host)
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,
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)
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)
156
inst = driver.encode_instance(updated_instance, local=True)
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
141
161
del request_spec['instance_properties']['uuid']
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.
170
retry = filter_properties.get('retry', None)
173
hosts = retry['hosts']
144
176
def _get_configuration_options(self):
145
177
"""Fetch options dictionary. Broken out for testing."""
146
178
return self.options.get_configuration()
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.
154
def _schedule(self, context, topic, request_spec, *args, **kwargs):
186
def _max_attempts(self):
187
max_attempts = FLAGS.scheduler_max_attempts
189
raise exception.NovaException(_("Invalid value for "
190
"'scheduler_max_attempts', must be >= 1"))
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.
197
max_attempts = self._max_attempts()
198
retry = filter_properties.pop('retry', {})
200
if max_attempts == 1:
201
# re-scheduling is disabled.
204
# retry is enabled, update attempt count:
206
retry['num_attempts'] += 1
210
'hosts': [] # list of compute hosts tried
212
filter_properties['retry'] = retry
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)
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.