def _VerifyInstance(self, instance, node_image, diskstatus):
    pnode_uuid = instance.primary_node
    pnode_img = node_image[pnode_uuid]
    groupinfo = self.cfg.GetAllNodeGroupsInfo()

    node_vol_should = {}
    self.cfg.GetInstanceLVsByNode(instance.uuid, lvmap=node_vol_should)

    cluster = self.cfg.GetClusterInfo()
    ipolicy = ganeti.masterd.instance.CalculateGroupIPolicy(cluster,
                                                            self.group_info)
    err = ComputeIPolicyInstanceViolation(ipolicy, instance, self.cfg)
    self._ErrorIf(err, constants.CV_EINSTANCEPOLICY, instance.name,
                  utils.CommaJoin(err), code=self.ETYPE_WARNING)

    for node_uuid in node_vol_should:
      n_img = node_image[node_uuid]
      if n_img.offline or n_img.rpc_fail or n_img.lvm_fail:
        # ignore missing volumes on offline or broken nodes
        continue
      for volume in node_vol_should[node_uuid]:
        test = volume not in n_img.volumes
        self._ErrorIf(test, constants.CV_EINSTANCEMISSINGDISK, instance.name,
                      "volume %s missing on node %s", volume,
                      self.cfg.GetNodeName(node_uuid))

    if instance.admin_state == constants.ADMINST_UP:
      test = instance.uuid not in pnode_img.instances and not pnode_img.offline
      self._ErrorIf(test, constants.CV_EINSTANCEDOWN, instance.name,
                    "instance not running on its primary node %s",
                     self.cfg.GetNodeName(pnode_uuid))
      self._ErrorIf(pnode_img.offline, constants.CV_EINSTANCEBADNODE,
                    instance.name, "instance is marked as running and lives on"
                    " offline node %s", self.cfg.GetNodeName(pnode_uuid))

    diskdata = [(nname, success, status, idx)
                for (nname, disks) in diskstatus.items()
                for idx, (success, status) in enumerate(disks)]

    for nname, success, bdev_status, idx in diskdata:
      # the 'ghost node' construction in Exec() ensures that we have a
      # node here
      snode = node_image[nname]
      bad_snode = snode.ghost or snode.offline
      self._ErrorIf(instance.disks_active and
                    not success and not bad_snode,
                    constants.CV_EINSTANCEFAULTYDISK, instance.name,
                    "couldn't retrieve status for disk/%s on %s: %s",
                    idx, self.cfg.GetNodeName(nname), bdev_status)

      if instance.disks_active and success and bdev_status.is_degraded:
        msg = "disk/%s on %s is degraded" % (idx, self.cfg.GetNodeName(nname))

        code = self.ETYPE_ERROR
        accepted_lds = [constants.LDS_OKAY, constants.LDS_SYNC]

        if bdev_status.ldisk_status in accepted_lds:
          code = self.ETYPE_WARNING

        msg += "; local disk state is '%s'" % \
                 constants.LDS_NAMES[bdev_status.ldisk_status]

        self._Error(constants.CV_EINSTANCEFAULTYDISK, instance.name, msg,
                    code=code)

    self._ErrorIf(pnode_img.rpc_fail and not pnode_img.offline,
                  constants.CV_ENODERPC, self.cfg.GetNodeName(pnode_uuid),
                  "instance %s, connection to primary node failed",
                  instance.name)

    secondary_nodes = self.cfg.GetInstanceSecondaryNodes(instance.uuid)
    self._ErrorIf(len(secondary_nodes) > 1,
                  constants.CV_EINSTANCELAYOUT, instance.name,
                  "instance has multiple secondary nodes: %s",
                  utils.CommaJoin(secondary_nodes),
                  code=self.ETYPE_WARNING)

    inst_nodes = self.cfg.GetInstanceNodes(instance.uuid)
    es_flags = rpc.GetExclusiveStorageForNodes(self.cfg, inst_nodes)
    disks = self.cfg.GetInstanceDisks(instance.uuid)
    if any(es_flags.values()):
      if not utils.AllDiskOfType(disks, constants.DTS_EXCL_STORAGE):
        # Disk template not compatible with exclusive_storage: no instance
        # node should have the flag set
        es_nodes = [n
                    for (n, es) in es_flags.items()
                    if es]
        unsupported = [d.dev_type for d in disks
                       if d.dev_type not in constants.DTS_EXCL_STORAGE]
        self._Error(constants.CV_EINSTANCEUNSUITABLENODE, instance.name,
                    "instance uses disk types %s, which are not supported on"
                    " nodes that have exclusive storage set: %s",
                    utils.CommaJoin(unsupported),
                    utils.CommaJoin(self.cfg.GetNodeNames(es_nodes)))
      for (idx, disk) in enumerate(disks):
        self._ErrorIf(disk.spindles is None,
                      constants.CV_EINSTANCEMISSINGCFGPARAMETER, instance.name,
                      "number of spindles not configured for disk %s while"
                      " exclusive storage is enabled, try running"
                      " gnt-cluster repair-disk-sizes", idx)

    if utils.AnyDiskOfType(disks, constants.DTS_INT_MIRROR):
      instance_nodes = utils.NiceSort(inst_nodes)
      instance_groups = {}

      for node_uuid in instance_nodes:
        instance_groups.setdefault(self.all_node_info[node_uuid].group,
                                   []).append(node_uuid)

      pretty_list = [
        "%s (group %s)" % (utils.CommaJoin(self.cfg.GetNodeNames(nodes)),
                           groupinfo[group].name)
        # Sort so that we always list the primary node first.
        for group, nodes in sorted(instance_groups.items(),
                                   key=lambda (_, nodes): pnode_uuid in nodes,
                                   reverse=True)]

      self._ErrorIf(len(instance_groups) > 1,
                    constants.CV_EINSTANCESPLITGROUPS,
                    instance.name, "instance has primary and secondary nodes in"
                    " different groups: %s", utils.CommaJoin(pretty_list),
                    code=self.ETYPE_WARNING)

    inst_nodes_offline = []
    for snode in secondary_nodes:
      s_img = node_image[snode]
      self._ErrorIf(s_img.rpc_fail and not s_img.offline, constants.CV_ENODERPC,
                    self.cfg.GetNodeName(snode),
                    "instance %s, connection to secondary node failed",
                    instance.name)

      if s_img.offline:
        inst_nodes_offline.append(snode)

    # warn that the instance lives on offline nodes
    self._ErrorIf(inst_nodes_offline, constants.CV_EINSTANCEBADNODE,
                  instance.name, "instance has offline secondary node(s) %s",
                  utils.CommaJoin(self.cfg.GetNodeNames(inst_nodes_offline)))
    # ... or ghost/non-vm_capable nodes
    for node_uuid in inst_nodes:
      self._ErrorIf(node_image[node_uuid].ghost, constants.CV_EINSTANCEBADNODE,
                    instance.name, "instance lives on ghost node %s",
                    self.cfg.GetNodeName(node_uuid))
      self._ErrorIf(not node_image[node_uuid].vm_capable,
                    constants.CV_EINSTANCEBADNODE, instance.name,
                    "instance lives on non-vm_capable node %s",
                    self.cfg.GetNodeName(node_uuid))
Verify an instance.
dataset/ETHPy150Open ganeti/ganeti/lib/cmdlib/cluster/verify.py/LUClusterVerifyGroup._VerifyInstance