/**
   * Verify the migration of BlockConsistencyGroups. Ensure the type and deviceName fields have been
   * migrated to the types and deviceNames fields.
   *
   * @param consistencyGroup
   * @param types The types that should have been properly migrated.
   * @throws Exception
   */
  private void verifyConsistencyGroupMigration(
      BlockConsistencyGroup consistencyGroup, String... types) throws Exception {
    log.info("Verifying BlockConsistencyGroup migration for " + consistencyGroup.getLabel());

    // Verify that the primary CG now has the VPlex type added to its types list is and that
    // the type field null
    Assert.assertTrue(
        "The BlockConsistencyGroup.type field should be null.",
        consistencyGroup.getType().equals(NullColumnValueGetter.getNullStr()));

    for (String type : types) {
      Assert.assertNotNull(
          "The " + type + " BlockConsistencyGroup.types field should be populated.",
          consistencyGroup.getTypes());
      Assert.assertTrue(
          "The BlockConsistencyGroup.types field for "
              + consistencyGroup.getLabel()
              + " should contain "
              + type,
          consistencyGroup.getTypes().contains(type));

      // Verify that the primary CG now has the RP and VPlex device names added to its list
      Assert.assertTrue(
          "The local array BlockConsistencyGroup.deviceName field should be null.",
          consistencyGroup.getDeviceName().equals(NullColumnValueGetter.getNullStr()));
    }
  }
  private void verifyEmptyConsistencyGroupMigration() throws Exception {
    log.info("Verifying empty/unused BlockConsistencyGroup.");
    BlockConsistencyGroup emptyCg = _dbClient.queryObject(BlockConsistencyGroup.class, emptyCgURI);

    // Verify that the primary CG now has the VPlex type added to its types list is null
    Assert.assertTrue(
        "The empty BlockConsistencyGroup.type field should be null.",
        emptyCg.getType().equals(NullColumnValueGetter.getNullStr()));

    Assert.assertTrue(
        "The BlockConsistencyGroup.types field should be null.", emptyCg.getTypes().isEmpty());
  }
  private static void renderTenantOptions() {
    if (TenantUtils.canReadAllTenantsForVcenters() && VCenterUtils.canUpdateACLs()) {
      List<StringOption> tenantOptions = dataObjectOptions(await(new TenantsCall().asPromise()));
      renderArgs.put("tenantOptions", tenantOptions);

      List<StringOption> tenantOptionsWithNone = new ArrayList<StringOption>();

      tenantOptionsWithNone.add(
          new StringOption(NullColumnValueGetter.getNullStr().toString(), "None"));
      tenantOptionsWithNone.addAll(tenantOptions);
      renderArgs.put("tenantOptionsWithNone", tenantOptionsWithNone);
    }
  }
  @Override
  protected void complete(DbClient dbClient, Status status, ServiceCoded coded)
      throws DeviceControllerException {
    if (isNotifyWorkflow()) {
      // If there is a workflow, update the step to complete.
      updateWorkflowStatus(status, coded);
    }

    // if export updates were successful, remove all old initiators and deleted hosts
    if (status.equals(Status.ready)) {
      for (HostStateChange hostChange : changes) {
        for (URI initiatorId : hostChange.getOldInitiators()) {
          Initiator initiator = dbClient.queryObject(Initiator.class, initiatorId);
          dbClient.markForDeletion(initiator);
          _logger.info("Initiator marked for deletion: " + this.getId());
        }
      }

      for (URI hostId : deletedHosts) {
        Host host = dbClient.queryObject(Host.class, hostId);
        // don't delete host if it was provisioned by Vipr
        if (!NullColumnValueGetter.isNullURI(host.getComputeElement())) {
          _logger.info(
              "do not delete provisioned host {} - disassociate it from vcenter", host.getLabel());
          host.setVcenterDataCenter(NullColumnValueGetter.getNullURI());
          dbClient.persistObject(host);
        } else {
          ComputeSystemHelper.doDeactivateHost(dbClient, host);
          _logger.info("Deactivating Host: " + host.getId());
        }
      }

      for (URI clusterId : deletedClusters) {
        Cluster cluster = dbClient.queryObject(Cluster.class, clusterId);
        List<URI> clusterHosts =
            ComputeSystemHelper.getChildrenUris(dbClient, clusterId, Host.class, "cluster");
        // don't delete cluster if all hosts weren't deleted (ex: hosts provisioned by ViPR)
        if (!clusterHosts.isEmpty()) {
          _logger.info(
              "do not delete cluster {} - it still has hosts - disassociate it from vcenter",
              cluster.getLabel());
          cluster.setVcenterDataCenter(NullColumnValueGetter.getNullURI());
          cluster.setExternalId(NullColumnValueGetter.getNullStr());
          dbClient.persistObject(cluster);
        } else {
          ComputeSystemHelper.doDeactivateCluster(dbClient, cluster);
          _logger.info("Deactivating Cluster: " + cluster.getId());
        }
      }
    }
  }
    public ACLAssignmentChanges getAclAssignmentChanges() {
      Set<String> tenantIds = Sets.newHashSet();

      if (this.cascadeTenancy) {
        if (StringUtils.isNotBlank(this.tenant)
            && !this.tenant.equalsIgnoreCase(NullColumnValueGetter.getNullStr().toString())) {
          tenantIds.add(this.tenant);
        }
      } else if (!CollectionUtils.isEmpty(this.tenants)) {
        tenantIds.addAll(this.tenants);
      }

      List<ACLEntry> existingAcls = new ArrayList<ACLEntry>();
      if (StringUtils.isNotBlank(this.id)) {
        existingAcls = VCenterUtils.getAcl(URI.create(this.id));
      }
      ACLUpdateBuilder builder = new ACLUpdateBuilder(existingAcls);
      builder.setTenants(tenantIds);

      return builder.getACLUpdate();
    }
  @Override
  public void deleteGroupMirrors(
      StorageSystem storage, List<URI> mirrorList, TaskCompleter taskCompleter)
      throws DeviceControllerException {
    _log.info("deleteGroupMirrors operation START");
    if (!((storage.getUsingSmis80() && storage.deviceIsType(Type.vmax))
        || storage.deviceIsType(Type.vnxblock))) {
      throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
    }

    try {
      String[] deviceIds = null;
      BlockMirror firstMirror = _dbClient.queryObject(BlockMirror.class, mirrorList.get(0));
      String repGroupName = firstMirror.getReplicationGroupInstance();
      if (NullColumnValueGetter.isNotNullValue(repGroupName)) {
        CIMObjectPath repGroupPath = _cimPath.getReplicationGroupPath(storage, repGroupName);
        Set<String> deviceIdsSet =
            _helper.getVolumeDeviceIdsFromStorageGroup(storage, repGroupPath);
        deviceIds = deviceIdsSet.toArray(new String[deviceIdsSet.size()]);

        // Delete replication group
        ReplicationUtils.deleteReplicationGroup(
            storage, repGroupName, _dbClient, _helper, _cimPath);
        // Set mirrors replication group to null
        List<BlockMirror> mirrors = _dbClient.queryObject(BlockMirror.class, mirrorList);
        for (BlockMirror mirror : mirrors) {
          mirror.setConsistencyGroup(NullColumnValueGetter.getNullURI());
          mirror.setReplicationGroupInstance(NullColumnValueGetter.getNullStr());
        }

        _dbClient.persistObject(mirrors);
      } else {
        deviceIds = _helper.getBlockObjectNativeIds(mirrorList);
      }

      if (storage.checkIfVmax3()) {
        for (String deviceId : deviceIds) {
          _helper.removeVolumeFromParkingSLOStorageGroup(storage, deviceId, false);
          _log.info("Done invoking remove volume {} from parking SLO storage group", deviceId);
        }
      }

      CIMObjectPath[] mirrorPaths = _cimPath.getVolumePaths(storage, deviceIds);
      CIMObjectPath configSvcPath = _cimPath.getConfigSvcPath(storage);
      CIMArgument[] inArgs = null;
      if (storage.deviceIsType(Type.vnxblock)) {
        inArgs = _helper.getReturnElementsToStoragePoolArguments(mirrorPaths);
      } else {
        inArgs =
            _helper.getReturnElementsToStoragePoolArguments(
                mirrorPaths, SmisConstants.CONTINUE_ON_NONEXISTENT_ELEMENT);
      }
      CIMArgument[] outArgs = new CIMArgument[5];
      _helper.invokeMethod(
          storage, configSvcPath, SmisConstants.RETURN_ELEMENTS_TO_STORAGE_POOL, inArgs, outArgs);
      CIMObjectPath job = _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.JOB);
      ControllerServiceImpl.enqueueJob(
          new QueueJob(new SmisBlockDeleteCGMirrorJob(job, storage.getId(), taskCompleter)));
    } catch (Exception e) {
      _log.error("Problem making SMI-S call: ", e);
      ServiceError serviceError =
          DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
      taskCompleter.error(_dbClient, serviceError);
    }
  }