components/openstack/nova/files/solariszones/driver.py
branchs11u3-sru
changeset 5413 bca6b9853ab7
parent 5412 8566c7ab4a73
child 5414 1697d1e334a5
equal deleted inserted replaced
5412:8566c7ab4a73 5413:bca6b9853ab7
     1 # Copyright 2011 Justin Santa Barbara
     1 # Copyright 2011 Justin Santa Barbara
     2 # All Rights Reserved.
     2 # All Rights Reserved.
     3 #
     3 #
     4 # Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
     4 # Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
     5 #
     5 #
     6 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     6 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     7 #    not use this file except in compliance with the License. You may obtain
     7 #    not use this file except in compliance with the License. You may obtain
     8 #    a copy of the License at
     8 #    a copy of the License at
     9 #
     9 #
    50 from nova.i18n import _
    50 from nova.i18n import _
    51 from nova.image import glance
    51 from nova.image import glance
    52 from nova.network import neutronv2
    52 from nova.network import neutronv2
    53 from nova import objects
    53 from nova import objects
    54 from nova.objects import flavor as flavor_obj
    54 from nova.objects import flavor as flavor_obj
       
    55 from nova.openstack.common import excutils
    55 from nova.openstack.common import fileutils
    56 from nova.openstack.common import fileutils
    56 from nova.openstack.common import jsonutils
    57 from nova.openstack.common import jsonutils
    57 from nova.openstack.common import log as logging
    58 from nova.openstack.common import log as logging
    58 from nova.openstack.common import loopingcall
    59 from nova.openstack.common import loopingcall
    59 from nova.openstack.common import processutils
    60 from nova.openstack.common import processutils
    67 
    68 
    68 solariszones_opts = [
    69 solariszones_opts = [
    69     cfg.StrOpt('glancecache_dirname',
    70     cfg.StrOpt('glancecache_dirname',
    70                default='$state_path/images',
    71                default='$state_path/images',
    71                help='Default path to Glance cache for Solaris Zones.'),
    72                help='Default path to Glance cache for Solaris Zones.'),
       
    73     cfg.StrOpt('live_migration_cipher',
       
    74                help='Cipher to use for encryption of memory traffic during '
       
    75                     'live migration. If not specified, a common encryption '
       
    76                     'algorithm will be negotiated. Options include: none or '
       
    77                     'the name of a supported OpenSSL cipher algorithm.'),
    72     cfg.StrOpt('solariszones_snapshots_directory',
    78     cfg.StrOpt('solariszones_snapshots_directory',
    73                default='$instances_path/snapshots',
    79                default='$instances_path/snapshots',
    74                help='Location where solariszones driver will store snapshots '
    80                help='Location to store snapshots before uploading them to the '
    75                     'before uploading them to the Glance image service'),
    81                     'Glance image service.'),
    76 ]
    82 ]
    77 
    83 
    78 CONF = cfg.CONF
    84 CONF = cfg.CONF
    79 CONF.register_opts(solariszones_opts)
    85 CONF.register_opts(solariszones_opts)
    80 CONF.import_opt('vncserver_proxyclient_address', 'nova.vnc')
    86 CONF.import_opt('vncserver_proxyclient_address', 'nova.vnc')
   119     ZONE_BRAND_SOLARIS:         'SYSdefault',
   125     ZONE_BRAND_SOLARIS:         'SYSdefault',
   120     ZONE_BRAND_SOLARIS_KZ:      'SYSsolaris-kz',
   126     ZONE_BRAND_SOLARIS_KZ:      'SYSsolaris-kz',
   121 }
   127 }
   122 
   128 
   123 MAX_CONSOLE_BYTES = 102400
   129 MAX_CONSOLE_BYTES = 102400
       
   130 
   124 VNC_CONSOLE_BASE_FMRI = 'svc:/application/openstack/nova/zone-vnc-console'
   131 VNC_CONSOLE_BASE_FMRI = 'svc:/application/openstack/nova/zone-vnc-console'
   125 # Required in order to create a zone VNC console SMF service instance
   132 # Required in order to create a zone VNC console SMF service instance
   126 VNC_SERVER_PATH = '/usr/bin/vncserver'
   133 VNC_SERVER_PATH = '/usr/bin/vncserver'
   127 XTERM_PATH = '/usr/bin/xterm'
   134 XTERM_PATH = '/usr/bin/xterm'
       
   135 
       
   136 # The underlying Solaris Zones framework does not expose a specific
       
   137 # version number, instead relying on feature tests to identify what is
       
   138 # and what is not supported. A HYPERVISOR_VERSION is defined here for
       
   139 # Nova's use but it generally should not be changed unless there is a
       
   140 # incompatible change such as concerning kernel zone live migration.
       
   141 HYPERVISOR_VERSION = '5.11'
   128 
   142 
   129 
   143 
   130 def lookup_resource_property(zone, resource, prop, filter=None):
   144 def lookup_resource_property(zone, resource, prop, filter=None):
   131     """Lookup specified property from specified Solaris Zone resource."""
   145     """Lookup specified property from specified Solaris Zone resource."""
   132     try:
   146     try:
  2242         else:
  2256         else:
  2243             free_disk_gb = 0
  2257             free_disk_gb = 0
  2244         host_stats['local_gb_used'] = host_stats['local_gb'] - free_disk_gb
  2258         host_stats['local_gb_used'] = host_stats['local_gb'] - free_disk_gb
  2245 
  2259 
  2246         host_stats['hypervisor_type'] = 'solariszones'
  2260         host_stats['hypervisor_type'] = 'solariszones'
  2247         host_stats['hypervisor_version'] = int(self._uname[2].replace('.', ''))
  2261         host_stats['hypervisor_version'] = \
       
  2262             utils.convert_version_to_int(HYPERVISOR_VERSION)
  2248         host_stats['hypervisor_hostname'] = self._uname[1]
  2263         host_stats['hypervisor_hostname'] = self._uname[1]
  2249 
  2264 
  2250         if self._uname[4] == 'i86pc':
  2265         if self._uname[4] == 'i86pc':
  2251             architecture = 'x86_64'
  2266             architecture = 'x86_64'
  2252         else:
  2267         else:
  2304         :param block_device_info: instance block device information
  2319         :param block_device_info: instance block device information
  2305         :param network_info: instance network information
  2320         :param network_info: instance network information
  2306         :param disk_info: instance disk information
  2321         :param disk_info: instance disk information
  2307         :param migrate_data: implementation specific data dict.
  2322         :param migrate_data: implementation specific data dict.
  2308         """
  2323         """
  2309         raise NotImplementedError()
  2324         return {}
       
  2325 
       
  2326     def _live_migration(self, name, dest, dry_run=False):
       
  2327         """Live migration of a Solaris kernel zone to another host."""
       
  2328         zone = self._get_zone_by_name(name)
       
  2329         if zone is None:
       
  2330             raise exception.InstanceNotFound(instance_id=name)
       
  2331 
       
  2332         options = []
       
  2333         live_migration_cipher = CONF.live_migration_cipher
       
  2334         if live_migration_cipher is not None:
       
  2335             options.extend(['-c', live_migration_cipher])
       
  2336         if dry_run:
       
  2337             options.append('-nq')
       
  2338         options.append('ssh://nova@' + dest)
       
  2339         zone.migrate(options)
  2310 
  2340 
  2311     def live_migration(self, context, instance, dest,
  2341     def live_migration(self, context, instance, dest,
  2312                        post_method, recover_method, block_migration=False,
  2342                        post_method, recover_method, block_migration=False,
  2313                        migrate_data=None):
  2343                        migrate_data=None):
  2314         """Live migration of an instance to another host.
  2344         """Live migration of an instance to another host.
  2326             expected nova.compute.manager._rollback_live_migration.
  2356             expected nova.compute.manager._rollback_live_migration.
  2327         :param block_migration: if true, migrate VM disk.
  2357         :param block_migration: if true, migrate VM disk.
  2328         :param migrate_data: implementation specific params.
  2358         :param migrate_data: implementation specific params.
  2329 
  2359 
  2330         """
  2360         """
  2331         raise NotImplementedError()
  2361         name = instance['name']
       
  2362         try:
       
  2363             self._live_migration(name, dest, dry_run=False)
       
  2364         except Exception as ex:
       
  2365             with excutils.save_and_reraise_exception():
       
  2366                 LOG.error(_("Unable to live migrate instance '%s' to host "
       
  2367                             "'%s' via zonemgr(3RAD): %s")
       
  2368                           % (name, dest, ex))
       
  2369                 recover_method(context, instance, dest, block_migration)
       
  2370 
       
  2371         post_method(context, instance, dest, block_migration, migrate_data)
  2332 
  2372 
  2333     def rollback_live_migration_at_destination(self, context, instance,
  2373     def rollback_live_migration_at_destination(self, context, instance,
  2334                                                network_info,
  2374                                                network_info,
  2335                                                block_device_info,
  2375                                                block_device_info,
  2336                                                destroy_disks=True,
  2376                                                destroy_disks=True,
  2344         :param destroy_disks:
  2384         :param destroy_disks:
  2345             if true, destroy disks at destination during cleanup
  2385             if true, destroy disks at destination during cleanup
  2346         :param migrate_data: implementation specific params
  2386         :param migrate_data: implementation specific params
  2347 
  2387 
  2348         """
  2388         """
  2349         raise NotImplementedError()
  2389         pass
  2350 
  2390 
  2351     def post_live_migration(self, context, instance, block_device_info,
  2391     def post_live_migration(self, context, instance, block_device_info,
  2352                             migrate_data=None):
  2392                             migrate_data=None):
  2353         """Post operation of live migration at source host.
  2393         """Post operation of live migration at source host.
  2354 
  2394 
  2355         :param context: security context
  2395         :param context: security context
  2356         :instance: instance object that was migrated
  2396         :instance: instance object that was migrated
  2357         :block_device_info: instance block device information
  2397         :block_device_info: instance block device information
  2358         :param migrate_data: if not None, it is a dict which has data
  2398         :param migrate_data: if not None, it is a dict which has data
  2359         """
  2399         """
  2360         pass
  2400         try:
       
  2401             # These methods log if problems occur so no need to double log
       
  2402             # here. Just catch any stray exceptions and allow destroy to
       
  2403             # proceed.
       
  2404             if self._has_vnc_console_service(instance):
       
  2405                 self._disable_vnc_console_service(instance)
       
  2406                 self._delete_vnc_console_service(instance)
       
  2407         except Exception:
       
  2408             pass
       
  2409 
       
  2410         name = instance['name']
       
  2411         zone = self._get_zone_by_name(name)
       
  2412         # If instance cannot be found, just return.
       
  2413         if zone is None:
       
  2414             LOG.warning(_("Unable to find instance '%s' via zonemgr(3RAD)")
       
  2415                         % name)
       
  2416             return
       
  2417 
       
  2418         try:
       
  2419             self._delete_config(instance)
       
  2420         except Exception as ex:
       
  2421             LOG.error(_("Unable to delete configuration for instance '%s' via "
       
  2422                         "zonemgr(3RAD): %s") % (name, ex))
       
  2423             raise
  2361 
  2424 
  2362     def post_live_migration_at_source(self, context, instance, network_info):
  2425     def post_live_migration_at_source(self, context, instance, network_info):
  2363         """Unplug VIFs from networks at source.
  2426         """Unplug VIFs from networks at source.
  2364 
  2427 
  2365         :param context: security context
  2428         :param context: security context
  2378         :param context: security context
  2441         :param context: security context
  2379         :param instance: instance object that is migrated
  2442         :param instance: instance object that is migrated
  2380         :param network_info: instance network information
  2443         :param network_info: instance network information
  2381         :param block_migration: if true, post operation of block_migration.
  2444         :param block_migration: if true, post operation of block_migration.
  2382         """
  2445         """
  2383         raise NotImplementedError()
  2446         pass
  2384 
  2447 
  2385     def check_instance_shared_storage_local(self, context, instance):
  2448     def check_instance_shared_storage_local(self, context, instance):
  2386         """Check if instance files located on shared storage.
  2449         """Check if instance files located on shared storage.
  2387 
  2450 
  2388         This runs check on the destination host, and then calls
  2451         This runs check on the destination host, and then calls
  2424         :param dst_compute_info: Info about the receiving machine
  2487         :param dst_compute_info: Info about the receiving machine
  2425         :param block_migration: if true, prepare for block migration
  2488         :param block_migration: if true, prepare for block migration
  2426         :param disk_over_commit: if true, allow disk over commit
  2489         :param disk_over_commit: if true, allow disk over commit
  2427         :returns: a dict containing migration info (hypervisor-dependent)
  2490         :returns: a dict containing migration info (hypervisor-dependent)
  2428         """
  2491         """
  2429         raise NotImplementedError()
  2492         src_cpu_info = jsonutils.loads(src_compute_info['cpu_info'])
       
  2493         src_cpu_arch = src_cpu_info['arch']
       
  2494         dst_cpu_info = jsonutils.loads(dst_compute_info['cpu_info'])
       
  2495         dst_cpu_arch = dst_cpu_info['arch']
       
  2496         if src_cpu_arch != dst_cpu_arch:
       
  2497             reason = (_("CPU architectures between source host '%s' (%s) and "
       
  2498                         "destination host '%s' (%s) are incompatible.")
       
  2499                       % (src_compute_info['hypervisor_hostname'], src_cpu_arch,
       
  2500                          dst_compute_info['hypervisor_hostname'],
       
  2501                          dst_cpu_arch))
       
  2502             raise exception.MigrationPreCheckError(reason=reason)
       
  2503 
       
  2504         extra_specs = self._get_extra_specs(instance)
       
  2505         brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS)
       
  2506         if brand != ZONE_BRAND_SOLARIS_KZ:
       
  2507             # Only Solaris kernel zones are currently supported.
       
  2508             reason = (_("'%s' branded zones do not currently support live "
       
  2509                         "migration.") % brand)
       
  2510             raise exception.MigrationPreCheckError(reason=reason)
       
  2511 
       
  2512         if block_migration:
       
  2513             reason = (_('Block migration is not currently supported.'))
       
  2514             raise exception.MigrationPreCheckError(reason=reason)
       
  2515         if disk_over_commit:
       
  2516             reason = (_('Disk overcommit is not currently supported.'))
       
  2517             raise exception.MigrationPreCheckError(reason=reason)
       
  2518 
       
  2519         dest_check_data = {
       
  2520             'hypervisor_hostname': dst_compute_info['hypervisor_hostname']
       
  2521         }
       
  2522         return dest_check_data
  2430 
  2523 
  2431     def check_can_live_migrate_destination_cleanup(self, context,
  2524     def check_can_live_migrate_destination_cleanup(self, context,
  2432                                                    dest_check_data):
  2525                                                    dest_check_data):
  2433         """Do required cleanup on dest host after check_can_live_migrate calls
  2526         """Do required cleanup on dest host after check_can_live_migrate calls
  2434 
  2527 
  2435         :param context: security context
  2528         :param context: security context
  2436         :param dest_check_data: result of check_can_live_migrate_destination
  2529         :param dest_check_data: result of check_can_live_migrate_destination
  2437         """
  2530         """
  2438         raise NotImplementedError()
  2531         pass
       
  2532 
       
  2533     def _check_local_volumes_present(self, block_device_info):
       
  2534         """Check if local volumes are attached to the instance."""
       
  2535         bmap = block_device_info.get('block_device_mapping')
       
  2536         for entry in bmap:
       
  2537             connection_info = entry['connection_info']
       
  2538             driver_type = connection_info['driver_volume_type']
       
  2539             if driver_type == 'local':
       
  2540                 reason = (_("Instances with attached '%s' volumes are not "
       
  2541                             "currently supported.") % driver_type)
       
  2542                 raise exception.MigrationPreCheckError(reason=reason)
  2439 
  2543 
  2440     def check_can_live_migrate_source(self, context, instance,
  2544     def check_can_live_migrate_source(self, context, instance,
  2441                                       dest_check_data):
  2545                                       dest_check_data, block_device_info):
  2442         """Check if it is possible to execute live migration.
  2546         """Check if it is possible to execute live migration.
  2443 
  2547 
  2444         This checks if the live migration can succeed, based on the
  2548         This checks if the live migration can succeed, based on the
  2445         results from check_can_live_migrate_destination.
  2549         results from check_can_live_migrate_destination.
  2446 
  2550 
  2447         :param context: security context
  2551         :param context: security context
  2448         :param instance: nova.db.sqlalchemy.models.Instance
  2552         :param instance: nova.db.sqlalchemy.models.Instance
  2449         :param dest_check_data: result of check_can_live_migrate_destination
  2553         :param dest_check_data: result of check_can_live_migrate_destination
       
  2554         :param block_device_info: result of _get_instance_block_device_info
  2450         :returns: a dict containing migration info (hypervisor-dependent)
  2555         :returns: a dict containing migration info (hypervisor-dependent)
  2451         """
  2556         """
  2452         raise NotImplementedError()
  2557         self._check_local_volumes_present(block_device_info)
       
  2558         name = instance['name']
       
  2559         dest = dest_check_data['hypervisor_hostname']
       
  2560         try:
       
  2561             self._live_migration(name, dest, dry_run=True)
       
  2562         except Exception as ex:
       
  2563             raise exception.MigrationPreCheckError(reason=ex)
       
  2564         return dest_check_data
  2453 
  2565 
  2454     def get_instance_disk_info(self, instance_name,
  2566     def get_instance_disk_info(self, instance_name,
  2455                                block_device_info=None):
  2567                                block_device_info=None):
  2456         """Retrieve information about actual disk sizes of an instance.
  2568         """Retrieve information about actual disk sizes of an instance.
  2457 
  2569 
  2576 
  2688 
  2577         :param instance: nova.objects.instance.Instance object
  2689         :param instance: nova.objects.instance.Instance object
  2578 
  2690 
  2579         """
  2691         """
  2580         # TODO(Vek): Need to pass context in for access to auth_token
  2692         # TODO(Vek): Need to pass context in for access to auth_token
  2581         raise NotImplementedError()
  2693         pass
  2582 
  2694 
  2583     def filter_defer_apply_on(self):
  2695     def filter_defer_apply_on(self):
  2584         """Defer application of IPTables rules."""
  2696         """Defer application of IPTables rules."""
  2585         pass
  2697         pass
  2586 
  2698 
  2589         pass
  2701         pass
  2590 
  2702 
  2591     def unfilter_instance(self, instance, network_info):
  2703     def unfilter_instance(self, instance, network_info):
  2592         """Stop filtering instance."""
  2704         """Stop filtering instance."""
  2593         # TODO(Vek): Need to pass context in for access to auth_token
  2705         # TODO(Vek): Need to pass context in for access to auth_token
  2594         raise NotImplementedError()
  2706         pass
  2595 
  2707 
  2596     def set_admin_password(self, instance, new_pass):
  2708     def set_admin_password(self, instance, new_pass):
  2597         """Set the root password on the specified instance.
  2709         """Set the root password on the specified instance.
  2598 
  2710 
  2599         :param instance: nova.objects.instance.Instance
  2711         :param instance: nova.objects.instance.Instance