components/openstack/nova/files/solariszones/driver.py
branchs11u3-sru
changeset 5414 1697d1e334a5
parent 5413 bca6b9853ab7
child 5429 1ae4cfbadda9
equal deleted inserted replaced
5413:bca6b9853ab7 5414:1697d1e334a5
   168     except rad.client.ObjectError:
   168     except rad.client.ObjectError:
   169         return None
   169         return None
   170     except Exception:
   170     except Exception:
   171         raise
   171         raise
   172 
   172 
       
   173 def zonemgr_strerror(ex):
       
   174     """Format the payload from a zonemgr(3RAD) rad.client.ObjectError
       
   175     exception into a sensible error string that can be logged. Newlines
       
   176     are converted to a colon-space string to create a single line.
       
   177 
       
   178     If the exception was something other than rad.client.ObjectError,
       
   179     just return it as a string.
       
   180     """
       
   181     if not isinstance(ex, rad.client.ObjectError):
       
   182         return str(ex)
       
   183     payload = ex.get_payload()
       
   184     if payload.code == zonemgr.ErrorCode.NONE:
       
   185         return str(ex)
       
   186     error = [str(payload.code)]
       
   187     if payload.str is not None and payload.str != '':
       
   188         error.append(payload.str)
       
   189     if payload.stderr is not None and payload.stderr != '':
       
   190         stderr = payload.stderr.rstrip()
       
   191         error.append(stderr.replace('\n', ': '))
       
   192     result = ': '.join(error)
       
   193     return result
       
   194 
   173 
   195 
   174 class ZoneConfig(object):
   196 class ZoneConfig(object):
   175     """ZoneConfig - context manager for access zone configurations.
   197     """ZoneConfig - context manager for access zone configurations.
   176     Automatically opens the configuration for a zone and commits any changes
   198     Automatically opens the configuration for a zone and commits any changes
   177     before exiting
   199     before exiting
   187         """enables the editing of the zone."""
   209         """enables the editing of the zone."""
   188         try:
   210         try:
   189             self.zone.editConfig()
   211             self.zone.editConfig()
   190             self.editing = True
   212             self.editing = True
   191             return self
   213             return self
   192         except rad.client.ObjectError as err:
   214         except Exception as ex:
       
   215             reason = zonemgr_strerror(ex)
   193             LOG.error(_("Unable to initialize editing of instance '%s' via "
   216             LOG.error(_("Unable to initialize editing of instance '%s' via "
   194                         "zonemgr(3RAD): %s") % (self.zone.name, err))
   217                         "zonemgr(3RAD): %s") % (self.zone.name, reason))
   195             raise
   218             raise
   196 
   219 
   197     def __exit__(self, exc_type, exc_val, exc_tb):
   220     def __exit__(self, exc_type, exc_val, exc_tb):
   198         """looks for any kind of exception before exiting.  If one is found,
   221         """looks for any kind of exception before exiting.  If one is found,
   199         cancel any configuration changes and reraise the exception.  If not,
   222         cancel any configuration changes and reraise the exception.  If not,
   205             raise
   228             raise
   206         else:
   229         else:
   207             # commit the config
   230             # commit the config
   208             try:
   231             try:
   209                 self.zone.commitConfig()
   232                 self.zone.commitConfig()
   210             except rad.client.ObjectError as err:
   233             except Exception as ex:
       
   234                 reason = zonemgr_strerror(ex)
   211                 LOG.error(_("Unable to commit the new configuration for "
   235                 LOG.error(_("Unable to commit the new configuration for "
   212                             "instance '%s' via zonemgr(3RAD): %s")
   236                             "instance '%s' via zonemgr(3RAD): %s")
   213                           % (self.zone.name, err))
   237                           % (self.zone.name, reason))
   214 
   238 
   215                 # Last ditch effort to cleanup.
   239                 # Last ditch effort to cleanup.
   216                 self.zone.cancelConfig()
   240                 self.zone.cancelConfig()
   217                 raise
   241                 raise
   218 
   242 
   231                     resource, [zonemgr.Property(prop, value)]))
   255                     resource, [zonemgr.Property(prop, value)]))
   232             else:
   256             else:
   233                 self.zone.setResourceProperties(
   257                 self.zone.setResourceProperties(
   234                     zonemgr.Resource(resource),
   258                     zonemgr.Resource(resource),
   235                     [zonemgr.Property(prop, value)])
   259                     [zonemgr.Property(prop, value)])
   236         except rad.client.ObjectError as err:
   260         except Exception as ex:
       
   261             reason = zonemgr_strerror(ex)
   237             LOG.error(_("Unable to set '%s' property on '%s' resource for "
   262             LOG.error(_("Unable to set '%s' property on '%s' resource for "
   238                         "instance '%s' via zonemgr(3RAD): %s")
   263                         "instance '%s' via zonemgr(3RAD): %s")
   239                       % (prop, resource, self.zone.name, err))
   264                       % (prop, resource, self.zone.name, reason))
   240             raise
   265             raise
   241 
   266 
   242     def addresource(self, resource, props=None):
   267     def addresource(self, resource, props=None):
   243         """creates a new resource with an optional property list."""
   268         """creates a new resource with an optional property list."""
   244         if props is None:
   269         if props is None:
   245             props = []
   270             props = []
   246 
   271 
   247         try:
   272         try:
   248             self.zone.addResource(zonemgr.Resource(resource, props))
   273             self.zone.addResource(zonemgr.Resource(resource, props))
   249         except rad.client.ObjectError as err:
   274         except Exception as ex:
       
   275             if isinstance(ex, rad.client.ObjectError):
       
   276                 code = ex.get_payload().code
       
   277                 if (ignore_exists and
       
   278                         code == zonemgr.ErrorCode.RESOURCE_ALREADY_EXISTS):
       
   279                     self.zone.setResourceProperties(zonemgr.Resource(
       
   280                         resource, None), props)
       
   281                     return
       
   282             reason = zonemgr_strerror(ex)
   250             LOG.error(_("Unable to create new resource '%s' for instance '%s'"
   283             LOG.error(_("Unable to create new resource '%s' for instance '%s'"
   251                         "via zonemgr(3RAD): %s")
   284                         "via zonemgr(3RAD): %s")
   252                       % (resource, self.zone.name, err))
   285                       % (resource, self.zone.name, reason))
   253             raise
   286             raise
   254 
   287 
   255     def removeresources(self, resource, props=None):
   288     def removeresources(self, resource, props=None):
   256         """removes resources whose properties include the optional property
   289         """removes resources whose properties include the optional property
   257         list specified in props.
   290         list specified in props.
   259         if props is None:
   292         if props is None:
   260             props = []
   293             props = []
   261 
   294 
   262         try:
   295         try:
   263             self.zone.removeResources(zonemgr.Resource(resource, props))
   296             self.zone.removeResources(zonemgr.Resource(resource, props))
   264         except rad.client.ObjectError as err:
   297         except Exception as ex:
       
   298             reason = zonemgr_strerror(ex)
   265             LOG.error(_("Unable to remove resource '%s' for instance '%s' via "
   299             LOG.error(_("Unable to remove resource '%s' for instance '%s' via "
   266                         "zonemgr(3RAD): %s") % (resource, self.zone.name, err))
   300                         "zonemgr(3RAD): %s")
       
   301                       % (resource, self.zone.name, reason))
   267             raise
   302             raise
   268 
   303 
   269 
   304 
   270 class SolarisZonesDriver(driver.ComputeDriver):
   305 class SolarisZonesDriver(driver.ComputeDriver):
   271     """Solaris Zones Driver using the zonemgr(3RAD) and kstat(3RAD) providers.
   306     """Solaris Zones Driver using the zonemgr(3RAD) and kstat(3RAD) providers.
   367             return self._fc_hbas
   402             return self._fc_hbas
   368 
   403 
   369         out = None
   404         out = None
   370         try:
   405         try:
   371             out, err = utils.execute('/usr/sbin/fcinfo', 'hba-port')
   406             out, err = utils.execute('/usr/sbin/fcinfo', 'hba-port')
   372         except processutils.ProcessExecutionError as err:
   407         except processutils.ProcessExecutionError:
   373             return []
   408             return []
   374 
   409 
   375         if out is None:
   410         if out is None:
   376             raise RuntimeError(_("Cannot find any Fibre Channel HBAs"))
   411             raise RuntimeError(_("Cannot find any Fibre Channel HBAs"))
   377 
   412 
   576         """
   611         """
   577         # TODO(Vek): Need to pass context in for access to auth_token
   612         # TODO(Vek): Need to pass context in for access to auth_token
   578         name = instance['name']
   613         name = instance['name']
   579         zone = self._get_zone_by_name(name)
   614         zone = self._get_zone_by_name(name)
   580         if zone is None:
   615         if zone is None:
   581             LOG.error(_("Unable to find instance '%s' via zonemgr(3RAD)")
       
   582                       % name)
       
   583             raise exception.InstanceNotFound(instance_id=name)
   616             raise exception.InstanceNotFound(instance_id=name)
   584         return {
   617         return {
   585             'state':    self._get_state(zone),
   618             'state':    self._get_state(zone),
   586             'max_mem':  self._get_max_mem(zone),
   619             'max_mem':  self._get_max_mem(zone),
   587             'mem':      self._get_mem(zone),
   620             'mem':      self._get_mem(zone),
   833             # Use suriadm(1M) to generate a Fibre Channel storage URI.
   866             # Use suriadm(1M) to generate a Fibre Channel storage URI.
   834             try:
   867             try:
   835                 out, err = utils.execute('/usr/sbin/suriadm', 'lookup-uri',
   868                 out, err = utils.execute('/usr/sbin/suriadm', 'lookup-uri',
   836                                          '-p', 'target=naa.%s' % target_wwn,
   869                                          '-p', 'target=naa.%s' % target_wwn,
   837                                          '-p', 'lun=%s' % target_lun)
   870                                          '-p', 'lun=%s' % target_lun)
   838             except processutils.ProcessExecutionError as err:
   871             except processutils.ProcessExecutionError as ex:
       
   872                 reason = ex.stderr
   839                 LOG.error(_("Lookup failure of Fibre Channel volume '%s', lun "
   873                 LOG.error(_("Lookup failure of Fibre Channel volume '%s', lun "
   840                           "%s: %s") % (target_wwn, target_lun, err.stderr))
   874                           "%s: %s") % (target_wwn, target_lun, reason))
   841                 raise
   875                 raise
   842 
   876 
   843             lines = out.split('\n')
   877             lines = out.split('\n')
   844             # Use the long form SURI on the second output line.
   878             # Use the long form SURI on the second output line.
   845             suri = lines[1].strip()
   879             suri = lines[1].strip()
  1184                 self._set_boot_device(name, connection_info, brand)
  1218                 self._set_boot_device(name, connection_info, brand)
  1185             self._set_num_cpu(name, instance['vcpus'], brand)
  1219             self._set_num_cpu(name, instance['vcpus'], brand)
  1186             self._set_memory_cap(name, instance['memory_mb'], brand)
  1220             self._set_memory_cap(name, instance['memory_mb'], brand)
  1187             self._set_network(context, name, instance, network_info, brand,
  1221             self._set_network(context, name, instance, network_info, brand,
  1188                               sc_dir)
  1222                               sc_dir)
  1189         except Exception as reason:
  1223         except Exception as ex:
       
  1224             reason = zonemgr_strerror(ex)
  1190             LOG.error(_("Unable to create configuration for instance '%s' via "
  1225             LOG.error(_("Unable to create configuration for instance '%s' via "
  1191                         "zonemgr(3RAD): %s") % (name, reason))
  1226                         "zonemgr(3RAD): %s") % (name, reason))
  1192             raise
  1227             raise
  1193 
  1228 
  1194     def _create_vnc_console_service(self, instance):
  1229     def _create_vnc_console_service(self, instance):
  1209         name = instance['name']
  1244         name = instance['name']
  1210         # TODO(npower): investigate using RAD instead of CLI invocation
  1245         # TODO(npower): investigate using RAD instead of CLI invocation
  1211         try:
  1246         try:
  1212             out, err = utils.execute('/usr/sbin/svccfg', '-s',
  1247             out, err = utils.execute('/usr/sbin/svccfg', '-s',
  1213                                      VNC_CONSOLE_BASE_FMRI, 'add', name)
  1248                                      VNC_CONSOLE_BASE_FMRI, 'add', name)
  1214         except processutils.ProcessExecutionError as err:
  1249         except processutils.ProcessExecutionError as ex:
  1215             if self._has_vnc_console_service(instance):
  1250             if self._has_vnc_console_service(instance):
  1216                 LOG.debug(_("Ignoring attempt to create existing zone VNC "
  1251                 LOG.debug(_("Ignoring attempt to create existing zone VNC "
  1217                             "console SMF service for instance '%s'") % name)
  1252                             "console SMF service for instance '%s'") % name)
  1218                 return
  1253                 return
  1219             else:
  1254             reason = ex.stderr
  1220                 LOG.error(_("Unable to create zone VNC console SMF service "
  1255             LOG.error(_("Unable to create zone VNC console SMF service "
  1221                             "'{0}': {1}").format(
  1256                         "'{0}': {1}").format(
  1222                                 VNC_CONSOLE_BASE_FMRI + ':' + name, err))
  1257                             VNC_CONSOLE_BASE_FMRI + ':' + name, reason))
  1223                 raise
  1258             raise
  1224 
  1259 
  1225     def _delete_vnc_console_service(self, instance):
  1260     def _delete_vnc_console_service(self, instance):
  1226         """Delete a VNC console SMF service for a Solaris Zone"""
  1261         """Delete a VNC console SMF service for a Solaris Zone"""
  1227         name = instance['name']
  1262         name = instance['name']
  1228         self._disable_vnc_console_service(instance)
  1263         self._disable_vnc_console_service(instance)
  1229         # TODO(npower): investigate using RAD instead of CLI invocation
  1264         # TODO(npower): investigate using RAD instead of CLI invocation
  1230         try:
  1265         try:
  1231             out, err = utils.execute('/usr/sbin/svccfg', '-s',
  1266             out, err = utils.execute('/usr/sbin/svccfg', '-s',
  1232                                      VNC_CONSOLE_BASE_FMRI, 'delete', '-f',
  1267                                      VNC_CONSOLE_BASE_FMRI, 'delete', '-f',
  1233                                      name)
  1268                                      name)
  1234         except processutils.ProcessExecutionError as err:
  1269         except processutils.ProcessExecutionError as ex:
  1235             if not self._has_vnc_console_service(instance):
  1270             if not self._has_vnc_console_service(instance):
  1236                 LOG.debug(_("Ignoring attempt to delete a non-existent zone "
  1271                 LOG.debug(_("Ignoring attempt to delete a non-existent zone "
  1237                             "VNC console SMF service for instance '%s'")
  1272                             "VNC console SMF service for instance '%s'")
  1238                           % name)
  1273                           % name)
  1239                 return
  1274                 return
  1240             else:
  1275             reason = ex.stderr
  1241                 LOG.error(_("Unable to delete zone VNC console SMF service "
  1276             LOG.error(_("Unable to delete zone VNC console SMF service '%s': "
  1242                             "'%s': %s")
  1277                         "%s")
  1243                           % (VNC_CONSOLE_BASE_FMRI + ':' + name, err))
  1278                       % (VNC_CONSOLE_BASE_FMRI + ':' + name, reason))
  1244                 raise
  1279             raise
  1245 
  1280 
  1246     def _enable_vnc_console_service(self, instance):
  1281     def _enable_vnc_console_service(self, instance):
  1247         """Enable a zone VNC console SMF service"""
  1282         """Enable a zone VNC console SMF service"""
  1248         name = instance['name']
  1283         name = instance['name']
  1249 
  1284 
  1257                                      'setprop', 'vnc/nova-enabled=true')
  1292                                      'setprop', 'vnc/nova-enabled=true')
  1258             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1293             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1259                                      'refresh')
  1294                                      'refresh')
  1260             out, err = utils.execute('/usr/sbin/svcadm', 'enable',
  1295             out, err = utils.execute('/usr/sbin/svcadm', 'enable',
  1261                                      console_fmri)
  1296                                      console_fmri)
  1262         except processutils.ProcessExecutionError as err:
  1297         except processutils.ProcessExecutionError as ex:
  1263             if not self._has_vnc_console_service(instance):
  1298             if not self._has_vnc_console_service(instance):
  1264                 LOG.debug(_("Ignoring attempt to enable a non-existent zone "
  1299                 LOG.debug(_("Ignoring attempt to enable a non-existent zone "
  1265                             "VNC console SMF service for instance '%s'")
  1300                             "VNC console SMF service for instance '%s'")
  1266                           % name)
  1301                           % name)
       
  1302                 return
       
  1303             reason = ex.stderr
  1267             LOG.error(_("Unable to start zone VNC console SMF service "
  1304             LOG.error(_("Unable to start zone VNC console SMF service "
  1268                         "'%s': %s") % (console_fmri, err))
  1305                         "'%s': %s") % (console_fmri, reason))
  1269             raise
  1306             raise
  1270 
  1307 
  1271         # Allow some time for the console service to come online.
  1308         # Allow some time for the console service to come online.
  1272         greenthread.sleep(2)
  1309         greenthread.sleep(2)
  1273         while True:
  1310         while True:
  1284                     raise exception.ConsoleNotFoundForInstance(
  1321                     raise exception.ConsoleNotFoundForInstance(
  1285                         instance_uuid=instance['uuid'])
  1322                         instance_uuid=instance['uuid'])
  1286                 # Wait for service state to transition to (hopefully) online
  1323                 # Wait for service state to transition to (hopefully) online
  1287                 # state or offline/maintenance states.
  1324                 # state or offline/maintenance states.
  1288                 greenthread.sleep(2)
  1325                 greenthread.sleep(2)
  1289             except processutils.ProcessExecutionError as err:
  1326             except processutils.ProcessExecutionError as ex:
       
  1327                 reason = ex.stderr
  1290                 LOG.error(_("Error querying state of zone VNC console SMF "
  1328                 LOG.error(_("Error querying state of zone VNC console SMF "
  1291                             "service '%s': %s") % (console_fmri, err))
  1329                             "service '%s': %s") % (console_fmri, reason))
  1292                 raise
  1330                 raise
  1293         # TODO(npower): investigate using RAD instead of CLI invocation
  1331         # TODO(npower): investigate using RAD instead of CLI invocation
  1294         try:
  1332         try:
  1295             # The console SMF service exits with SMF_TEMP_DISABLE to prevent
  1333             # The console SMF service exits with SMF_TEMP_DISABLE to prevent
  1296             # unnecessarily coming online at boot. Make that happen.
  1334             # unnecessarily coming online at boot. Make that happen.
  1297             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1335             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1298                                      'setprop', 'vnc/nova-enabled=false')
  1336                                      'setprop', 'vnc/nova-enabled=false')
  1299             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1337             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1300                                      'refresh')
  1338                                      'refresh')
  1301         except processutils.ProcessExecutionError as err:
  1339         except processutils.ProcessExecutionError as ex:
       
  1340             reason = ex.stderr
  1302             LOG.error(_("Unable to update 'vnc/nova-enabled' property for "
  1341             LOG.error(_("Unable to update 'vnc/nova-enabled' property for "
  1303                         "zone VNC console SMF service "
  1342                         "zone VNC console SMF service "
  1304                         "'%s': %s") % (console_fmri, err))
  1343                         "'%s': %s") % (console_fmri, reason))
  1305             raise
  1344             raise
  1306 
  1345 
  1307     def _disable_vnc_console_service(self, instance):
  1346     def _disable_vnc_console_service(self, instance):
  1308         """Disable a zone VNC console SMF service"""
  1347         """Disable a zone VNC console SMF service"""
  1309         name = instance['name']
  1348         name = instance['name']
  1314         console_fmri = VNC_CONSOLE_BASE_FMRI + ':' + name
  1353         console_fmri = VNC_CONSOLE_BASE_FMRI + ':' + name
  1315         # TODO(npower): investigate using RAD instead of CLI invocation
  1354         # TODO(npower): investigate using RAD instead of CLI invocation
  1316         try:
  1355         try:
  1317             out, err = utils.execute('/usr/sbin/svcadm', 'disable',
  1356             out, err = utils.execute('/usr/sbin/svcadm', 'disable',
  1318                                      console_fmri)
  1357                                      console_fmri)
  1319         except processutils.ProcessExecutionError as err:
  1358         except processutils.ProcessExecutionError as ex:
       
  1359             reason = ex.stderr
  1320             LOG.error(_("Unable to disable zone VNC console SMF service "
  1360             LOG.error(_("Unable to disable zone VNC console SMF service "
  1321                         "'%s': %s") % (console_fmri, err))
  1361                         "'%s': %s") % (console_fmri, reason))
  1322         # The console service sets a SMF instance property for the port
  1362         # The console service sets a SMF instance property for the port
  1323         # on which the VNC service is listening. The service needs to be
  1363         # on which the VNC service is listening. The service needs to be
  1324         # refreshed to reset the property value
  1364         # refreshed to reset the property value
  1325         try:
  1365         try:
  1326             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1366             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1327                                      'refresh')
  1367                                      'refresh')
  1328         except processutils.ProcessExecutionError as err:
  1368         except processutils.ProcessExecutionError as ex:
       
  1369             reason = ex.stderr
  1329             LOG.error(_("Unable to refresh zone VNC console SMF service "
  1370             LOG.error(_("Unable to refresh zone VNC console SMF service "
  1330                         "'%s': %s") % (console_fmri, err))
  1371                         "'%s': %s") % (console_fmri, reason))
  1331 
  1372 
  1332     def _get_vnc_console_service_state(self, instance):
  1373     def _get_vnc_console_service_state(self, instance):
  1333         """Returns state of the instance zone VNC console SMF service"""
  1374         """Returns state of the instance zone VNC console SMF service"""
  1334         name = instance['name']
  1375         name = instance['name']
  1335         if not self._has_vnc_console_service(instance):
  1376         if not self._has_vnc_console_service(instance):
  1341         # TODO(npower): investigate using RAD instead of CLI invocation
  1382         # TODO(npower): investigate using RAD instead of CLI invocation
  1342         try:
  1383         try:
  1343             state, err = utils.execute('/usr/sbin/svcs', '-H', '-o', 'state',
  1384             state, err = utils.execute('/usr/sbin/svcs', '-H', '-o', 'state',
  1344                                        console_fmri)
  1385                                        console_fmri)
  1345             return state.strip()
  1386             return state.strip()
  1346         except processutils.ProcessExecutionError as err:
  1387         except processutils.ProcessExecutionError as ex:
       
  1388             reason = ex.stderr
  1347             LOG.error(_("Console state request failed for zone VNC console "
  1389             LOG.error(_("Console state request failed for zone VNC console "
  1348                         "SMF service for instance '%s': %s") % (name, err))
  1390                         "SMF service for instance '%s': %s")
       
  1391                       % (name, reason))
  1349             raise
  1392             raise
  1350 
  1393 
  1351     def _has_vnc_console_service(self, instance):
  1394     def _has_vnc_console_service(self, instance):
  1352         """Returns True if the instance has a zone VNC console SMF service"""
  1395         """Returns True if the instance has a zone VNC console SMF service"""
  1353         name = instance['name']
  1396         name = instance['name']
  1355         # TODO(npower): investigate using RAD instead of CLI invocation
  1398         # TODO(npower): investigate using RAD instead of CLI invocation
  1356         try:
  1399         try:
  1357             utils.execute('/usr/bin/svcs', '-H', '-o', 'state',
  1400             utils.execute('/usr/bin/svcs', '-H', '-o', 'state',
  1358                           console_fmri)
  1401                           console_fmri)
  1359             return True
  1402             return True
  1360         except processutils.ProcessExecutionError as err:
  1403         except Exception:
  1361             return False
  1404             return False
  1362 
  1405 
  1363     def _install(self, instance, image, sc_dir):
  1406     def _install(self, instance, image, sc_dir):
  1364         """Install a new Solaris Zone root file system."""
  1407         """Install a new Solaris Zone root file system."""
  1365         name = instance['name']
  1408         name = instance['name']
  1381 
  1424 
  1382         try:
  1425         try:
  1383             LOG.debug(_("Installing instance '%s' (%s)") %
  1426             LOG.debug(_("Installing instance '%s' (%s)") %
  1384                       (name, instance['display_name']))
  1427                       (name, instance['display_name']))
  1385             zone.install(options=options)
  1428             zone.install(options=options)
  1386         except Exception as reason:
  1429         except Exception as ex:
       
  1430             reason = zonemgr_strerror(ex)
  1387             LOG.error(_("Unable to install root file system for instance '%s' "
  1431             LOG.error(_("Unable to install root file system for instance '%s' "
  1388                         "via zonemgr(3RAD): %s") % (name, reason))
  1432                         "via zonemgr(3RAD): %s") % (name, reason))
  1389             raise
  1433             raise
  1390 
  1434 
  1391         LOG.debug(_("Installation of instance '%s' (%s) complete") %
  1435         LOG.debug(_("Installation of instance '%s' (%s) complete") %
  1398         if zone is None:
  1442         if zone is None:
  1399             raise exception.InstanceNotFound(instance_id=name)
  1443             raise exception.InstanceNotFound(instance_id=name)
  1400 
  1444 
  1401         try:
  1445         try:
  1402             zone.boot()
  1446             zone.boot()
  1403         except Exception as reason:
  1447         except Exception as ex:
       
  1448             reason = zonemgr_strerror(ex)
  1404             LOG.error(_("Unable to power on instance '%s' via zonemgr(3RAD): "
  1449             LOG.error(_("Unable to power on instance '%s' via zonemgr(3RAD): "
  1405                         "%s") % (name, reason))
  1450                         "%s") % (name, reason))
  1406             raise exception.InstancePowerOnFailure(reason=reason)
  1451             raise exception.InstancePowerOnFailure(reason=reason)
  1407 
  1452 
  1408     def _uninstall(self, instance):
  1453     def _uninstall(self, instance):
  1416             LOG.debug(_("Uninstall not required for zone '%s' in state '%s'")
  1461             LOG.debug(_("Uninstall not required for zone '%s' in state '%s'")
  1417                       % (name, zone.state))
  1462                       % (name, zone.state))
  1418             return
  1463             return
  1419         try:
  1464         try:
  1420             zone.uninstall(['-F'])
  1465             zone.uninstall(['-F'])
  1421         except Exception as reason:
  1466         except Exception as ex:
       
  1467             reason = zonemgr_strerror(ex)
  1422             LOG.error(_("Unable to uninstall root file system for instance "
  1468             LOG.error(_("Unable to uninstall root file system for instance "
  1423                         "'%s' via zonemgr(3RAD): %s") % (name, reason))
  1469                         "'%s' via zonemgr(3RAD): %s") % (name, reason))
  1424             raise
  1470             raise
  1425 
  1471 
  1426     def _delete_config(self, instance):
  1472     def _delete_config(self, instance):
  1430             raise exception.InstanceNotFound(instance_id=name)
  1476             raise exception.InstanceNotFound(instance_id=name)
  1431 
  1477 
  1432         zonemanager = self.rad_connection.get_object(zonemgr.ZoneManager())
  1478         zonemanager = self.rad_connection.get_object(zonemgr.ZoneManager())
  1433         try:
  1479         try:
  1434             zonemanager.delete(name)
  1480             zonemanager.delete(name)
  1435         except Exception as reason:
  1481         except Exception as ex:
       
  1482             reason = zonemgr_strerror(ex)
  1436             LOG.error(_("Unable to delete configuration for instance '%s' via "
  1483             LOG.error(_("Unable to delete configuration for instance '%s' via "
  1437                         "zonemgr(3RAD): %s") % (name, reason))
  1484                         "zonemgr(3RAD): %s") % (name, reason))
  1438             raise
  1485             raise
  1439 
  1486 
  1440     def spawn(self, context, instance, image_meta, injected_files,
  1487     def spawn(self, context, instance, image_meta, injected_files,
  1477         mountpoint = "c1d0"
  1524         mountpoint = "c1d0"
  1478         name = instance['name']
  1525         name = instance['name']
  1479         try:
  1526         try:
  1480             connection_info = self._connect_boot_volume(volume, mountpoint,
  1527             connection_info = self._connect_boot_volume(volume, mountpoint,
  1481                                                         context, instance)
  1528                                                         context, instance)
  1482         except exception.InvalidVolume as badvol:
  1529         except exception.InvalidVolume as reason:
  1483             # This Cinder volume is not usable for ZOSS so discard it.
  1530             # This Cinder volume is not usable for ZOSS so discard it.
  1484             # zonecfg will apply default zonepath dataset configuration
  1531             # zonecfg will apply default zonepath dataset configuration
  1485             # instead. Carry on
  1532             # instead. Carry on
  1486             LOG.warning(_("Volume '%s' is being discarded: %s")
  1533             LOG.warning(_("Volume '%s' is being discarded: %s")
  1487                         % (volume_id, badvol))
  1534                         % (volume_id, reason))
  1488             self._volume_api.delete(context, volume_id)
  1535             self._volume_api.delete(context, volume_id)
  1489             connection_info = None
  1536             connection_info = None
  1490         except Exception as reason:
  1537         except Exception as reason:
  1491             # Something really bad happened. Don't pass Go.
  1538             # Something really bad happened. Don't pass Go.
  1492             LOG.error(_("Unable to attach root zpool volume '%s' to instance "
  1539             LOG.error(_("Unable to attach root zpool volume '%s' to instance "
  1503                                 connection_info, sc_dir)
  1550                                 connection_info, sc_dir)
  1504             configured = True
  1551             configured = True
  1505             self._install(instance, image, sc_dir)
  1552             self._install(instance, image, sc_dir)
  1506             installed = True
  1553             installed = True
  1507             self._power_on(instance)
  1554             self._power_on(instance)
  1508         except Exception as reason:
  1555         except Exception as ex:
       
  1556             reason = zonemgr_strerror(ex)
  1509             LOG.error(_("Unable to spawn instance '%s' via zonemgr(3RAD): %s")
  1557             LOG.error(_("Unable to spawn instance '%s' via zonemgr(3RAD): %s")
  1510                       % (name, reason))
  1558                       % (name, reason))
  1511             if installed:
  1559             if installed:
  1512                 self._uninstall(instance)
  1560                 self._uninstall(instance)
  1513             if configured:
  1561             if configured:
  1543             if halt_type == 'SOFT':
  1591             if halt_type == 'SOFT':
  1544                 zone.shutdown()
  1592                 zone.shutdown()
  1545             else:
  1593             else:
  1546                 # 'HARD'
  1594                 # 'HARD'
  1547                 zone.halt()
  1595                 zone.halt()
  1548         except rad.client.ObjectError as reason:
  1596         except Exception as ex:
  1549             result = reason.get_payload()
  1597             reason = zonemgr_strerror(ex)
  1550             if result.code == zonemgr.ErrorCode.COMMAND_ERROR:
  1598             if isinstance(ex, rad.client.ObjectError):
  1551                 LOG.warning(_("Ignoring command error returned while trying "
  1599                 code = ex.get_payload().code
  1552                               "to power off instance '%s' via zonemgr(3RAD): "
  1600                 if code == zonemgr.ErrorCode.COMMAND_ERROR:
  1553                               "%s" % (name, reason)))
  1601                     LOG.warning(_("Ignoring command error returned while "
  1554                 return
  1602                                   "trying to power off instance '%s' via "
  1555         except Exception as reason:
  1603                                   "zonemgr(3RAD): %s" % (name, reason)))
       
  1604                     return
  1556             LOG.error(_("Unable to power off instance '%s' via zonemgr(3RAD): "
  1605             LOG.error(_("Unable to power off instance '%s' via zonemgr(3RAD): "
  1557                         "%s") % (name, reason))
  1606                         "%s") % (name, reason))
  1558             raise exception.InstancePowerOffFailure(reason=reason)
  1607             raise exception.InstancePowerOffFailure(reason=reason)
  1559 
  1608 
  1560     def destroy(self, context, instance, network_info, block_device_info=None,
  1609     def destroy(self, context, instance, network_info, block_device_info=None,
  1597                 self._power_off(instance, 'HARD')
  1646                 self._power_off(instance, 'HARD')
  1598             if self._get_state(zone) == power_state.SHUTDOWN:
  1647             if self._get_state(zone) == power_state.SHUTDOWN:
  1599                 self._uninstall(instance)
  1648                 self._uninstall(instance)
  1600             if self._get_state(zone) == power_state.NOSTATE:
  1649             if self._get_state(zone) == power_state.NOSTATE:
  1601                 self._delete_config(instance)
  1650                 self._delete_config(instance)
  1602         except Exception as reason:
  1651         except Exception as ex:
       
  1652             reason = zonemgr_strerror(ex)
  1603             LOG.warning(_("Unable to destroy instance '%s' via zonemgr(3RAD): "
  1653             LOG.warning(_("Unable to destroy instance '%s' via zonemgr(3RAD): "
  1604                           "%s") % (name, reason))
  1654                           "%s") % (name, reason))
  1605 
  1655 
  1606     def cleanup(self, context, instance, network_info, block_device_info=None,
  1656     def cleanup(self, context, instance, network_info, block_device_info=None,
  1607                 destroy_disks=True, migrate_data=None, destroy_vifs=True):
  1657                 destroy_disks=True, migrate_data=None, destroy_vifs=True):
  1651         try:
  1701         try:
  1652             if reboot_type == 'SOFT':
  1702             if reboot_type == 'SOFT':
  1653                 zone.shutdown(['-r'])
  1703                 zone.shutdown(['-r'])
  1654             else:
  1704             else:
  1655                 zone.reboot()
  1705                 zone.reboot()
  1656         except Exception as reason:
  1706         except Exception as ex:
       
  1707             reason = zonemgr_strerror(ex)
  1657             LOG.error(_("Unable to reboot instance '%s' via zonemgr(3RAD): %s")
  1708             LOG.error(_("Unable to reboot instance '%s' via zonemgr(3RAD): %s")
  1658                       % (name, reason))
  1709                       % (name, reason))
  1659             raise exception.InstanceRebootFailure(reason=reason)
  1710             raise exception.InstanceRebootFailure(reason=reason)
  1660 
  1711 
  1661     def get_console_pool_info(self, console_type):
  1712     def get_console_pool_info(self, console_type):
  1739         # refreshed to reflect the current property value
  1790         # refreshed to reflect the current property value
  1740         # TODO(npower): investigate using RAD instead of CLI invocation
  1791         # TODO(npower): investigate using RAD instead of CLI invocation
  1741         try:
  1792         try:
  1742             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1793             out, err = utils.execute('/usr/sbin/svccfg', '-s', console_fmri,
  1743                                      'refresh')
  1794                                      'refresh')
  1744         except processutils.ProcessExecutionError as err:
  1795         except processutils.ProcessExecutionError as ex:
       
  1796             reason = ex.stderr
  1745             LOG.error(_("Unable to refresh zone VNC console SMF service "
  1797             LOG.error(_("Unable to refresh zone VNC console SMF service "
  1746                         "'%s': %s" % (console_fmri, err)))
  1798                         "'%s': %s" % (console_fmri, reason)))
  1747             raise
  1799             raise
  1748 
  1800 
  1749         host = CONF.vncserver_proxyclient_address
  1801         host = CONF.vncserver_proxyclient_address
  1750         try:
  1802         try:
  1751             out, err = utils.execute('/usr/bin/svcprop', '-p', 'vnc/port',
  1803             out, err = utils.execute('/usr/bin/svcprop', '-p', 'vnc/port',
  1752                                      console_fmri)
  1804                                      console_fmri)
  1753             port = int(out.strip())
  1805             port = int(out.strip())
  1754             return ctype.ConsoleVNC(host=host,
  1806             return ctype.ConsoleVNC(host=host,
  1755                                     port=port,
  1807                                     port=port,
  1756                                     internal_access_path=None)
  1808                                     internal_access_path=None)
  1757         except processutils.ProcessExecutionError as err:
  1809         except processutils.ProcessExecutionError as ex:
       
  1810             reason = ex.stderr
  1758             LOG.error(_("Unable to read VNC console port from zone VNC "
  1811             LOG.error(_("Unable to read VNC console port from zone VNC "
  1759                         "console SMF service '%s': %s"
  1812                         "console SMF service '%s': %s"
  1760                       % (console_fmri, err)))
  1813                       % (console_fmri, reason)))
  1761 
  1814 
  1762     def get_spice_console(self, context, instance):
  1815     def get_spice_console(self, context, instance):
  1763         """Get connection info for a spice console.
  1816         """Get connection info for a spice console.
  1764 
  1817 
  1765         :param context: security context
  1818         :param context: security context
  1827         """
  1880         """
  1828         # TODO(Vek): Need to pass context in for access to auth_token
  1881         # TODO(Vek): Need to pass context in for access to auth_token
  1829         name = instance['name']
  1882         name = instance['name']
  1830         zone = self._get_zone_by_name(name)
  1883         zone = self._get_zone_by_name(name)
  1831         if zone is None:
  1884         if zone is None:
  1832             LOG.error(_("Unable to find instance '%s' via zonemgr(3RAD)")
       
  1833                       % name)
       
  1834             raise exception.InstanceNotFound(instance_id=name)
  1885             raise exception.InstanceNotFound(instance_id=name)
  1835         return self._get_zone_diagnostics(zone)
  1886         return self._get_zone_diagnostics(zone)
  1836 
  1887 
  1837     def get_instance_diagnostics(self, instance):
  1888     def get_instance_diagnostics(self, instance):
  1838         """Return data about VM diagnostics.
  1889         """Return data about VM diagnostics.
  2028                     metadata['disk_format'] = 'zfs'
  2079                     metadata['disk_format'] = 'zfs'
  2029                     snapshot_service.update(context,
  2080                     snapshot_service.update(context,
  2030                                             image_id,
  2081                                             image_id,
  2031                                             metadata,
  2082                                             metadata,
  2032                                             None)
  2083                                             None)
  2033                 except exception.Invalid as invalid:
  2084                 except exception.Invalid:
  2034                     LOG.warning(_("Image service rejected image metadata "
  2085                     LOG.warning(_("Image service rejected image metadata "
  2035                                   "container and disk formats 'uar' and "
  2086                                   "container and disk formats 'uar' and "
  2036                                   "'zfs'. Using generic values 'ovf' and "
  2087                                   "'zfs'. Using generic values 'ovf' and "
  2037                                   "'raw' as fallbacks."))
  2088                                   "'raw' as fallbacks."))
  2038             finally:
  2089             finally:
  2203     def _get_zpool_property(self, prop, zpool):
  2254     def _get_zpool_property(self, prop, zpool):
  2204         """Get the value of property from the zpool."""
  2255         """Get the value of property from the zpool."""
  2205         try:
  2256         try:
  2206             value = None
  2257             value = None
  2207             (out, _err) = utils.execute('/usr/sbin/zpool', 'get', prop, zpool)
  2258             (out, _err) = utils.execute('/usr/sbin/zpool', 'get', prop, zpool)
  2208         except processutils.ProcessExecutionError as err:
  2259         except processutils.ProcessExecutionError as ex:
       
  2260             reason = ex.stderr
  2209             LOG.error(_("Failed to get property '%s' from zpool '%s': %s")
  2261             LOG.error(_("Failed to get property '%s' from zpool '%s': %s")
  2210                       % (prop, zpool, err.stderr))
  2262                       % (prop, zpool, reason))
  2211             return value
  2263             return value
  2212 
  2264 
  2213         zpool_prop = out.splitlines()[1].split()
  2265         zpool_prop = out.splitlines()[1].split()
  2214         if zpool_prop[1] == prop:
  2266         if zpool_prop[1] == prop:
  2215             value = zpool_prop[2]
  2267             value = zpool_prop[2]
  2361         name = instance['name']
  2413         name = instance['name']
  2362         try:
  2414         try:
  2363             self._live_migration(name, dest, dry_run=False)
  2415             self._live_migration(name, dest, dry_run=False)
  2364         except Exception as ex:
  2416         except Exception as ex:
  2365             with excutils.save_and_reraise_exception():
  2417             with excutils.save_and_reraise_exception():
       
  2418                 reason = zonemgr_strerror(ex)
  2366                 LOG.error(_("Unable to live migrate instance '%s' to host "
  2419                 LOG.error(_("Unable to live migrate instance '%s' to host "
  2367                             "'%s' via zonemgr(3RAD): %s")
  2420                             "'%s' via zonemgr(3RAD): %s")
  2368                           % (name, dest, ex))
  2421                           % (name, dest, reason))
  2369                 recover_method(context, instance, dest, block_migration)
  2422                 recover_method(context, instance, dest, block_migration)
  2370 
  2423 
  2371         post_method(context, instance, dest, block_migration, migrate_data)
  2424         post_method(context, instance, dest, block_migration, migrate_data)
  2372 
  2425 
  2373     def rollback_live_migration_at_destination(self, context, instance,
  2426     def rollback_live_migration_at_destination(self, context, instance,
  2416             return
  2469             return
  2417 
  2470 
  2418         try:
  2471         try:
  2419             self._delete_config(instance)
  2472             self._delete_config(instance)
  2420         except Exception as ex:
  2473         except Exception as ex:
       
  2474             reason = zonemgr_strerror(ex)
  2421             LOG.error(_("Unable to delete configuration for instance '%s' via "
  2475             LOG.error(_("Unable to delete configuration for instance '%s' via "
  2422                         "zonemgr(3RAD): %s") % (name, ex))
  2476                         "zonemgr(3RAD): %s") % (name, reason))
  2423             raise
  2477             raise
  2424 
  2478 
  2425     def post_live_migration_at_source(self, context, instance, network_info):
  2479     def post_live_migration_at_source(self, context, instance, network_info):
  2426         """Unplug VIFs from networks at source.
  2480         """Unplug VIFs from networks at source.
  2427 
  2481 
  2558         name = instance['name']
  2612         name = instance['name']
  2559         dest = dest_check_data['hypervisor_hostname']
  2613         dest = dest_check_data['hypervisor_hostname']
  2560         try:
  2614         try:
  2561             self._live_migration(name, dest, dry_run=True)
  2615             self._live_migration(name, dest, dry_run=True)
  2562         except Exception as ex:
  2616         except Exception as ex:
  2563             raise exception.MigrationPreCheckError(reason=ex)
  2617             reason = zonemgr_strerror(ex)
       
  2618             raise exception.MigrationPreCheckError(reason=reason)
  2564         return dest_check_data
  2619         return dest_check_data
  2565 
  2620 
  2566     def get_instance_disk_info(self, instance_name,
  2621     def get_instance_disk_info(self, instance_name,
  2567                                block_device_info=None):
  2622                                block_device_info=None):
  2568         """Retrieve information about actual disk sizes of an instance.
  2623         """Retrieve information about actual disk sizes of an instance.