49 from oslo_utils import fileutils |
49 from oslo_utils import fileutils |
50 from oslo_utils import strutils |
50 from oslo_utils import strutils |
51 from oslo_utils import versionutils |
51 from oslo_utils import versionutils |
52 from passlib.hash import sha256_crypt |
52 from passlib.hash import sha256_crypt |
53 |
53 |
|
54 from nova.api.metadata import base as instance_metadata |
54 from nova.api.metadata import password |
55 from nova.api.metadata import password |
55 from nova.compute import arch |
56 from nova.compute import arch |
56 from nova.compute import hv_type |
57 from nova.compute import hv_type |
57 from nova.compute import power_state |
58 from nova.compute import power_state |
58 from nova.compute import task_states |
59 from nova.compute import task_states |
70 from nova.network.neutronv2 import api as neutronv2_api |
71 from nova.network.neutronv2 import api as neutronv2_api |
71 from nova import objects |
72 from nova import objects |
72 from nova.objects import flavor as flavor_obj |
73 from nova.objects import flavor as flavor_obj |
73 from nova.objects import migrate_data as migrate_data_obj |
74 from nova.objects import migrate_data as migrate_data_obj |
74 from nova import utils |
75 from nova import utils |
|
76 from nova.virt import configdrive |
75 from nova.virt import driver |
77 from nova.virt import driver |
76 from nova.virt import event as virtevent |
78 from nova.virt import event as virtevent |
77 from nova.virt import hardware |
79 from nova.virt import hardware |
78 from nova.virt import images |
80 from nova.virt import images |
79 from nova.virt.solariszones import sysconfig |
81 from nova.virt.solariszones import sysconfig |
1476 else: |
1478 else: |
1477 zc.addresource(ROOTZPOOL_RESOURCE, |
1479 zc.addresource(ROOTZPOOL_RESOURCE, |
1478 [zonemgr.Property("storage", listvalue=[suri])], |
1480 [zonemgr.Property("storage", listvalue=[suri])], |
1479 ignore_exists=True) |
1481 ignore_exists=True) |
1480 |
1482 |
|
1483 def _get_configdrive_path(self, instance): |
|
1484 cd_name = "config_drive-" + instance['name'] |
|
1485 |
|
1486 return os.path.join("/var/share/nova/configdrives", cd_name) |
|
1487 |
|
1488 def _set_configdrive(self, name, instance, sc_dir): |
|
1489 """Set the configdrive device""" |
|
1490 zone = self._get_zone_by_name(name) |
|
1491 if zone is None: |
|
1492 raise exception.InstanceNotFound(instance_id=name) |
|
1493 |
|
1494 cd_path = self._get_configdrive_path(instance) |
|
1495 |
|
1496 with ZoneConfig(zone) as zc: |
|
1497 storagepath = "file://root:root@" + cd_path |
|
1498 zc.addresource("device", [zonemgr.Property("storage", storagepath), |
|
1499 zonemgr.Property("id", "1")]) |
|
1500 |
|
1501 fp = os.path.join(sc_dir, "config_drive.xml") |
|
1502 tree = sysconfig.create_config_drive() |
|
1503 sysconfig.create_sc_profile(fp, tree) |
|
1504 |
|
1505 def _unset_configdrive(self, name, instance): |
|
1506 """ Remove the configdrive device from the zone""" |
|
1507 zone = self._get_zone_by_name(name) |
|
1508 if zone is None: |
|
1509 raise exception.InstanceNotFound(instance_id=name) |
|
1510 |
|
1511 cd_path = self._get_configdrive_path(instance) |
|
1512 |
|
1513 with ZoneConfig(zone) as zc: |
|
1514 storagepath = "file://root:root@" + cd_path |
|
1515 zc.removeresources("device", |
|
1516 [zonemgr.Property("storage", storagepath)]) |
|
1517 |
|
1518 if zone.state == ZONE_STATE_RUNNING: |
|
1519 zone.apply() |
|
1520 |
|
1521 os.remove(cd_path) |
|
1522 |
1481 def _set_num_cpu(self, name, vcpus, brand): |
1523 def _set_num_cpu(self, name, vcpus, brand): |
1482 """Set number of VCPUs in a Solaris Zone configuration.""" |
1524 """Set number of VCPUs in a Solaris Zone configuration.""" |
1483 zone = self._get_zone_by_name(name) |
1525 zone = self._get_zone_by_name(name) |
1484 if zone is None: |
1526 if zone is None: |
1485 raise exception.InstanceNotFound(instance_id=name) |
1527 raise exception.InstanceNotFound(instance_id=name) |
1893 self._set_boot_device(name, connection_info, brand) |
1935 self._set_boot_device(name, connection_info, brand) |
1894 self._set_num_cpu(name, instance['vcpus'], brand) |
1936 self._set_num_cpu(name, instance['vcpus'], brand) |
1895 self._set_memory_cap(name, instance['memory_mb'], brand) |
1937 self._set_memory_cap(name, instance['memory_mb'], brand) |
1896 self._set_network(context, name, instance, network_info, brand, |
1938 self._set_network(context, name, instance, network_info, brand, |
1897 sc_dir) |
1939 sc_dir) |
|
1940 if configdrive.required_by(instance): |
|
1941 self._set_configdrive(name, instance, sc_dir) |
1898 except Exception as ex: |
1942 except Exception as ex: |
1899 reason = zonemgr_strerror(ex) |
1943 reason = zonemgr_strerror(ex) |
1900 LOG.exception(_("Unable to create configuration for instance '%s' " |
1944 LOG.exception(_("Unable to create configuration for instance '%s' " |
1901 "via zonemgr(3RAD): %s") % (name, reason)) |
1945 "via zonemgr(3RAD): %s") % (name, reason)) |
1902 raise |
1946 raise |
2197 reason = zonemgr_strerror(ex) |
2241 reason = zonemgr_strerror(ex) |
2198 LOG.exception(_("Unable to delete configuration for instance '%s' " |
2242 LOG.exception(_("Unable to delete configuration for instance '%s' " |
2199 "via zonemgr(3RAD): %s") % (name, reason)) |
2243 "via zonemgr(3RAD): %s") % (name, reason)) |
2200 raise |
2244 raise |
2201 |
2245 |
|
2246 def _waitfor_copydone(self, name): |
|
2247 failcount = 0 |
|
2248 cbi_service = 'svc:/application/cloudbase-init:default' |
|
2249 cbi_state = None |
|
2250 end_states = ['online', 'degraded', 'maintenance', 'disabled'] |
|
2251 while cbi_state not in end_states: |
|
2252 try: |
|
2253 cbi_state, err = utils.execute('/usr/sbin/zlogin', '-S', name, |
|
2254 '/usr/bin/svcs', '-H', '-o', |
|
2255 'state', cbi_service) |
|
2256 cbi_state = cbi_state.strip() |
|
2257 except processutils.ProcessExecutionError: |
|
2258 # If it has been two minutes and the zone is still not able to |
|
2259 # return any kind of state, and the zlogin is failing, then |
|
2260 # simply get out of the process of protecting the config-drive |
|
2261 # but leave it attached to the zone. |
|
2262 if failcount > 120: |
|
2263 return False |
|
2264 |
|
2265 failcount = failcount + 1 |
|
2266 greenthread.sleep(1) |
|
2267 continue |
|
2268 |
|
2269 if cbi_state == "disabled" and cbi_state in end_states: |
|
2270 out, err = utils.execute('/usr/sbin/zlogin', '-S', name, |
|
2271 '/usr/bin/svcprop', '-p', |
|
2272 'general/enabled', cbi_service) |
|
2273 out = out.strip() |
|
2274 if out == "true": |
|
2275 end_states.remove('disabled') |
|
2276 |
|
2277 if cbi_state == "offline*": |
|
2278 out, err = utils.execute('/usr/sbin/zlogin', '-S', name, |
|
2279 '/usr/bin/svcprop', '-C', '-p', |
|
2280 'configdrive/copydone', cbi_service) |
|
2281 out = out.strip() |
|
2282 if out == "true": |
|
2283 break |
|
2284 |
|
2285 return True |
|
2286 |
2202 def spawn(self, context, instance, image_meta, injected_files, |
2287 def spawn(self, context, instance, image_meta, injected_files, |
2203 admin_password, network_info=None, block_device_info=None): |
2288 admin_password, network_info=None, block_device_info=None): |
2204 """Create a new instance/VM/domain on the virtualization platform. |
2289 """Create a new instance/VM/domain on the virtualization platform. |
2205 |
2290 |
2206 Once this successfully completes, the instance should be |
2291 Once this successfully completes, the instance should be |
2268 # create a new directory for SC profiles |
2353 # create a new directory for SC profiles |
2269 sc_dir = tempfile.mkdtemp(prefix="nova-sysconfig-", |
2354 sc_dir = tempfile.mkdtemp(prefix="nova-sysconfig-", |
2270 dir=CONF.state_path) |
2355 dir=CONF.state_path) |
2271 os.chmod(sc_dir, 0755) |
2356 os.chmod(sc_dir, 0755) |
2272 |
2357 |
|
2358 # Create the configdrive if required. |
|
2359 if configdrive.required_by(instance): |
|
2360 instance_md = instance_metadata.InstanceMetadata( |
|
2361 instance, |
|
2362 content=injected_files) |
|
2363 with configdrive.ConfigDriveBuilder(instance_md=instance_md) as cd: |
|
2364 cd_path = self._get_configdrive_path(instance) |
|
2365 try: |
|
2366 cd.make_drive(cd_path) |
|
2367 except Exception as e: |
|
2368 LOG.info(_("Failed to create config drive '%s'" % cd_path)) |
|
2369 |
2273 try: |
2370 try: |
2274 self._create_config(context, instance, network_info, |
2371 self._create_config(context, instance, network_info, |
2275 connection_info, sc_dir, admin_password) |
2372 connection_info, sc_dir, admin_password) |
2276 self._install(instance, image, sc_dir) |
2373 self._install(instance, image, sc_dir) |
2277 |
2374 |
2279 if entry['connection_info'] is not None: |
2376 if entry['connection_info'] is not None: |
2280 self.attach_volume(context, entry['connection_info'], |
2377 self.attach_volume(context, entry['connection_info'], |
2281 instance, entry['mount_device']) |
2378 instance, entry['mount_device']) |
2282 |
2379 |
2283 self._power_on(instance, network_info) |
2380 self._power_on(instance, network_info) |
|
2381 if configdrive.required_by(instance): |
|
2382 unset = self._waitfor_copydone(name) |
|
2383 if unset: |
|
2384 self._unset_configdrive(name, instance) |
2284 except Exception as ex: |
2385 except Exception as ex: |
2285 reason = zonemgr_strerror(ex) |
2386 reason = zonemgr_strerror(ex) |
2286 LOG.exception(_("Unable to spawn instance '%s' via zonemgr(3RAD): " |
2387 LOG.exception(_("Unable to spawn instance '%s' via zonemgr(3RAD): " |
2287 "'%s'") % (name, reason)) |
2388 "'%s'") % (name, reason)) |
2288 # At least attempt to uninstall the instance, depending on where |
2389 # At least attempt to uninstall the instance, depending on where |
2437 self._power_off(instance, 'HARD') |
2538 self._power_off(instance, 'HARD') |
2438 if self._get_state(zone) == power_state.SHUTDOWN: |
2539 if self._get_state(zone) == power_state.SHUTDOWN: |
2439 self._uninstall(instance) |
2540 self._uninstall(instance) |
2440 if self._get_state(zone) == power_state.NOSTATE: |
2541 if self._get_state(zone) == power_state.NOSTATE: |
2441 self._delete_config(instance) |
2542 self._delete_config(instance) |
|
2543 if configdrive.required_by(instance): |
|
2544 # Make sure that we don't leave any dirt around. |
|
2545 cd_path = self._get_configdrive_path(instance) |
|
2546 try: |
|
2547 os.remove(cd_path) |
|
2548 except OSError: |
|
2549 pass |
|
2550 |
2442 except Exception as ex: |
2551 except Exception as ex: |
2443 reason = zonemgr_strerror(ex) |
2552 reason = zonemgr_strerror(ex) |
2444 LOG.warning(_("Unable to destroy instance '%s' via zonemgr(3RAD): " |
2553 LOG.warning(_("Unable to destroy instance '%s' via zonemgr(3RAD): " |
2445 "%s") % (name, reason)) |
2554 "%s") % (name, reason)) |
2446 |
2555 |