Coverage for nova/conductor/api.py: 92%
57 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
1# Copyright 2012 IBM Corp.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
15"""Handles all requests to the conductor service."""
17from oslo_log import log as logging
18import oslo_messaging as messaging
20from nova import baserpc
21from nova.conductor import rpcapi
22import nova.conf
23from nova.image import glance
25CONF = nova.conf.CONF
27LOG = logging.getLogger(__name__)
30class API(object):
31 """Conductor API that does updates via RPC to the ConductorManager."""
33 def __init__(self):
34 self.conductor_rpcapi = rpcapi.ConductorAPI()
35 self.base_rpcapi = baserpc.BaseAPI(topic=rpcapi.RPC_TOPIC)
37 def object_backport_versions(self, context, objinst, object_versions):
38 return self.conductor_rpcapi.object_backport_versions(context, objinst,
39 object_versions)
41 def wait_until_ready(self, context, early_timeout=10, early_attempts=10):
42 '''Wait until a conductor service is up and running.
44 This method calls the remote ping() method on the conductor topic until
45 it gets a response. It starts with a shorter timeout in the loop
46 (early_timeout) up to early_attempts number of tries. It then drops
47 back to the globally configured timeout for rpc calls for each retry.
48 '''
49 attempt = 0
50 timeout = early_timeout
51 # if we show the timeout message, make sure we show a similar
52 # message saying that everything is now working to avoid
53 # confusion
54 has_timedout = False
55 while True:
56 # NOTE(danms): Try ten times with a short timeout, and then punt
57 # to the configured RPC timeout after that
58 if attempt == early_attempts:
59 timeout = None
60 attempt += 1
62 # NOTE(russellb): This is running during service startup. If we
63 # allow an exception to be raised, the service will shut down.
64 # This may fail the first time around if nova-conductor wasn't
65 # running when this service started.
66 try:
67 self.base_rpcapi.ping(context, '1.21 GigaWatts',
68 timeout=timeout)
69 if has_timedout: 69 ↛ 72line 69 didn't jump to line 72 because the condition on line 69 was always true
70 LOG.info('nova-conductor connection '
71 'established successfully')
72 break
73 except messaging.MessagingTimeout:
74 has_timedout = True
75 LOG.warning('Timed out waiting for nova-conductor. '
76 'Is it running? Or did this service start '
77 'before nova-conductor? '
78 'Reattempting establishment of '
79 'nova-conductor connection...')
82class ComputeTaskAPI(object):
83 """ComputeTask API that queues up compute tasks for nova-conductor."""
85 def __init__(self):
86 self.conductor_compute_rpcapi = rpcapi.ComputeTaskAPI()
87 self.image_api = glance.API()
89 # TODO(stephenfin): Remove the 'reservations' parameter since we don't use
90 # reservations anymore
91 def resize_instance(self, context, instance, scheduler_hint, flavor,
92 reservations=None, clean_shutdown=True,
93 request_spec=None, host_list=None, do_cast=False):
94 self.conductor_compute_rpcapi.migrate_server(
95 context, instance, scheduler_hint, live=False, rebuild=False,
96 flavor=flavor, block_migration=None, disk_over_commit=None,
97 reservations=reservations, clean_shutdown=clean_shutdown,
98 request_spec=request_spec, host_list=host_list,
99 do_cast=do_cast)
101 def live_migrate_instance(self, context, instance, host_name,
102 block_migration, disk_over_commit,
103 request_spec=None, async_=False):
104 scheduler_hint = {'host': host_name}
105 if async_: 105 ↛ 106line 105 didn't jump to line 106 because the condition on line 105 was never true
106 self.conductor_compute_rpcapi.live_migrate_instance(
107 context, instance, scheduler_hint, block_migration,
108 disk_over_commit, request_spec)
109 else:
110 self.conductor_compute_rpcapi.migrate_server(
111 context, instance, scheduler_hint, True, False, None,
112 block_migration, disk_over_commit, None,
113 request_spec=request_spec)
115 def build_instances(self, context, instances, image, filter_properties,
116 admin_password, injected_files, requested_networks,
117 security_groups, block_device_mapping, legacy_bdm=True,
118 request_spec=None, host_lists=None):
119 self.conductor_compute_rpcapi.build_instances(context,
120 instances=instances, image=image,
121 filter_properties=filter_properties,
122 admin_password=admin_password, injected_files=injected_files,
123 requested_networks=requested_networks,
124 security_groups=security_groups,
125 block_device_mapping=block_device_mapping,
126 legacy_bdm=legacy_bdm, request_spec=request_spec,
127 host_lists=host_lists)
129 def schedule_and_build_instances(self, context, build_requests,
130 request_spec, image,
131 admin_password, injected_files,
132 requested_networks, block_device_mapping,
133 tags=None):
134 self.conductor_compute_rpcapi.schedule_and_build_instances(
135 context, build_requests, request_spec, image,
136 admin_password, injected_files, requested_networks,
137 block_device_mapping, tags)
139 def unshelve_instance(self, context, instance, request_spec=None):
140 self.conductor_compute_rpcapi.unshelve_instance(context,
141 instance=instance, request_spec=request_spec)
143 def rebuild_instance(self, context, instance, orig_image_ref, image_ref,
144 injected_files, new_pass, orig_sys_metadata,
145 bdms, recreate=False, on_shared_storage=False,
146 preserve_ephemeral=False, host=None,
147 request_spec=None, reimage_boot_volume=False,
148 target_state=None):
149 self.conductor_compute_rpcapi.rebuild_instance(context,
150 instance=instance,
151 new_pass=new_pass,
152 injected_files=injected_files,
153 image_ref=image_ref,
154 orig_image_ref=orig_image_ref,
155 orig_sys_metadata=orig_sys_metadata,
156 bdms=bdms,
157 recreate=recreate,
158 on_shared_storage=on_shared_storage,
159 preserve_ephemeral=preserve_ephemeral,
160 host=host,
161 request_spec=request_spec,
162 reimage_boot_volume=reimage_boot_volume,
163 target_state=target_state)
165 def cache_images(self, context, aggregate, image_ids):
166 """Request images be pre-cached on hosts within an aggregate.
168 :param context: The RequestContext
169 :param aggregate: The objects.Aggregate representing the hosts to
170 contact
171 :param image_ids: A list of image ID strings to send to the hosts
172 """
173 for image_id in image_ids:
174 # Validate that we can get the image by id before we go
175 # ask a bunch of hosts to do the same. We let this bubble
176 # up to the API, which catches NovaException for the 4xx and
177 # otherwise 500s if this fails in some unexpected way.
178 self.image_api.get(context, image_id)
179 self.conductor_compute_rpcapi.cache_images(context, aggregate,
180 image_ids)
182 def confirm_snapshot_based_resize(
183 self, ctxt, instance, migration, do_cast=True):
184 self.conductor_compute_rpcapi.confirm_snapshot_based_resize(
185 ctxt, instance, migration, do_cast=do_cast)
187 def revert_snapshot_based_resize(
188 self, ctxt, instance, migration):
189 self.conductor_compute_rpcapi.revert_snapshot_based_resize(
190 ctxt, instance, migration)