@Override
  public void removeVcenterCluster(URI datacenterUri, URI clusterUri) throws InternalException {
    VcenterApiClient vcenterApiClient = null;
    try {
      VcenterDataCenter vcenterDataCenter =
          _dbClient.queryObject(VcenterDataCenter.class, datacenterUri);
      Cluster cluster = _dbClient.queryObject(Cluster.class, clusterUri);
      Vcenter vcenter = _dbClient.queryObject(Vcenter.class, vcenterDataCenter.getVcenter());
      _log.info(
          "Request to remove cluster "
              + vcenter.getLabel()
              + "/"
              + vcenterDataCenter.getLabel()
              + "/"
              + cluster.getLabel());

      vcenterApiClient = new VcenterApiClient(_coordinator.getPropertyInfo());
      vcenterApiClient.setup(vcenter.getIpAddress(), vcenter.getUsername(), vcenter.getPassword());
      vcenterApiClient.removeCluster(vcenterDataCenter.getLabel(), cluster.getExternalId());
    } catch (VcenterObjectConnectionException e) {
      throw VcenterControllerException.exceptions.objectConnectionException(
          e.getLocalizedMessage(), e);
    } catch (VcenterObjectNotFoundException e) {
      throw VcenterControllerException.exceptions.objectNotFoundException(
          e.getLocalizedMessage(), e);
    } catch (VcenterServerConnectionException e) {
      throw VcenterControllerException.exceptions.serverConnectionException(
          e.getLocalizedMessage(), e);
    } catch (Exception e) {
      _log.error("removeVcenterCluster exception " + e);
      throw VcenterControllerException.exceptions.unexpectedException(e.getLocalizedMessage(), e);
    } finally {
      if (vcenterApiClient != null) vcenterApiClient.destroy();
    }
  }
  /**
   * Adds the tenant to the vCenter acls if the tenant admin is creating it. This always sets the
   * vCenter tenant (the old deprecated filed to null).
   *
   * @param tenant a valid tenant org if the tenant admin is creating it.
   * @param vcenter the vCenter being created.
   */
  private void addVcenterAclIfTenantAdmin(TenantOrg tenant, Vcenter vcenter) {
    // Always set the deprecated tenant field of a vCenter to null.
    vcenter.setTenant(NullColumnValueGetter.getNullURI());

    if (isSystemAdmin()) {
      return;
    }

    URI tenantId;
    if (tenant != null) {
      tenantId = tenant.getId();
    } else {
      // If the tenant org is not valid, try to use the
      // user's tenant org.
      tenantId = URI.create(getUserFromContext().getTenantId());
    }

    // If the User is an admin in the tenant org, allow the
    // operation otherwise, report the insufficient permission
    // exception.
    if (_permissionsHelper.userHasGivenRole(getUserFromContext(), tenantId, Role.TENANT_ADMIN)) {
      // Generate the acl entry and add to the vCenters acls.
      String aclKey = _permissionsHelper.getTenantUsePermissionKey(tenantId.toString());
      vcenter.addAcl(aclKey, ACL.USE.name());
      _log.debug("Adding {} to the vCenter {} acls", aclKey, vcenter.getLabel());
    }
  }
  /**
   * Filters the vCenters by the tenant. If the provided tenant is null or the tenant does not share
   * the vCenter than the vCenters are filtered with the user's tenant.
   *
   * @param vcenters to be filtered by the tenant.
   * @param tenantId to be used for filtering the vCenter.
   * @return the list of vCenters that belong to the tenantId or the user's tenant org.
   */
  private List<Vcenter> filterVcentersByTenant(List<Vcenter> vcenters, URI tenantId) {
    List<Vcenter> tenantVcenterList = new ArrayList<Vcenter>();
    Iterator<Vcenter> vcenterIt = vcenters.iterator();
    while (vcenterIt.hasNext()) {
      Vcenter vcenter = vcenterIt.next();
      if (vcenter == null) {
        continue;
      }

      Set<URI> tenantUris = _permissionsHelper.getUsageURIsFromAcls(vcenter.getAcls());
      if (CollectionUtils.isEmpty(tenantUris)) {
        continue;
      }

      if (!NullColumnValueGetter.isNullURI(tenantId) && !tenantUris.contains(tenantId)) {
        // The tenantId is not a null URI and it is not available in the vCenter acls,
        // so, dont add to the filtered list.
        continue;
      }

      Iterator<URI> tenantUriIt = tenantUris.iterator();
      while (tenantUriIt.hasNext()) {
        if (verifyAuthorizedInTenantOrg(tenantUriIt.next())) {
          tenantVcenterList.add(vcenter);
        }
      }
    }
    return tenantVcenterList;
  }
  public void vcenterClusterAddHostOperation(
      URI vcenterId, URI vcenterDataCenterId, URI clusterId, URI hostId, String stepId) {
    VcenterApiClient vcenterApiClient = null;
    try {
      WorkflowStepCompleter.stepExecuting(stepId);

      VcenterDataCenter vcenterDataCenter =
          _dbClient.queryObject(VcenterDataCenter.class, vcenterDataCenterId);
      Cluster cluster = _dbClient.queryObject(Cluster.class, clusterId);
      Vcenter vcenter = _dbClient.queryObject(Vcenter.class, vcenterId);
      Host host = _dbClient.queryObject(Host.class, hostId);

      vcenterApiClient = new VcenterApiClient(_coordinator.getPropertyInfo());
      vcenterApiClient.setup(vcenter.getIpAddress(), vcenter.getUsername(), vcenter.getPassword());
      String key =
          vcenterApiClient.addHost(
              vcenterDataCenter.getLabel(),
              cluster.getExternalId(),
              host.getHostName(),
              host.getUsername(),
              host.getPassword());
      _log.info("Successfully added or located host " + host.getHostName() + " " + key);

      host.setVcenterDataCenter(vcenterDataCenter.getId());
      _dbClient.updateAndReindexObject(host);

      WorkflowStepCompleter.stepSucceded(stepId);
    } catch (Exception e) {
      _log.error("vcenterClusterAddHostOperation exception " + e);
      WorkflowStepCompleter.stepFailed(
          stepId, VcenterControllerException.exceptions.hostException(e.getLocalizedMessage(), e));
    } finally {
      if (vcenterApiClient != null) vcenterApiClient.destroy();
    }
  }
 /**
  * Creates a new vCenter data center.
  *
  * @param id the URN of the parent vCenter
  * @param createParam the details of the data center
  * @prereq none
  * @brief Create vCenter data center
  * @return the details of the vCenter data center, including its id and link, when creation
  *     completes successfully.
  * @throws DatabaseException when a database error occurs.
  */
 @POST
 @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.TENANT_ADMIN})
 @Path("/{id}/vcenter-data-centers")
 public VcenterDataCenterRestRep createVcenterDataCenter(
     @PathParam("id") URI id, VcenterDataCenterCreate createParam) throws DatabaseException {
   Vcenter vcenter = queryObject(Vcenter.class, id, false);
   checkDuplicateChildName(
       id,
       VcenterDataCenter.class,
       DATAOBJECT_NAME_FIELD,
       "vcenter",
       createParam.getName(),
       _dbClient);
   VcenterDataCenter datacenter = new VcenterDataCenter();
   datacenter.setId(URIUtil.createId(VcenterDataCenter.class));
   datacenter.setLabel(createParam.getName());
   datacenter.setVcenter(id);
   if (vcenter.getTenantCreated()) {
     datacenter.setTenant(_permissionsHelper.getTenant(vcenter.getAcls()));
   } else {
     datacenter.setTenant(NullColumnValueGetter.getNullURI());
   }
   _dbClient.createObject(datacenter);
   auditOp(OperationTypeEnum.CREATE_VCENTER_DATACENTER, true, null, datacenter.auditParameters());
   return map(datacenter);
 }
  /**
   * Deactivates the vCenter, its vCenter data centers, clusters and hosts.
   *
   * @param id the URN of a ViPR vCenter to be deactivated
   * @prereq none
   * @brief Delete vCenter
   * @return OK if deactivation completed successfully
   * @throws DatabaseException when a DB error occurs
   */
  @POST
  @Path("/{id}/deactivate")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.TENANT_ADMIN})
  public TaskResourceRep deactivateVcenter(
      @PathParam("id") URI id,
      @DefaultValue("false") @QueryParam("detach-storage") boolean detachStorage)
      throws DatabaseException {
    if (ComputeSystemHelper.isVcenterInUse(_dbClient, id) && !detachStorage) {
      throw APIException.badRequests.resourceHasActiveReferences(Vcenter.class.getSimpleName(), id);
    } else {
      Vcenter vcenter = queryObject(Vcenter.class, id, true);

      // check the user permissions for this tenant org
      verifyAuthorizedSystemOrTenantOrgUser(
          _permissionsHelper.convertToACLEntries(vcenter.getAcls()));

      checkIfOtherTenantsUsingTheVcenter(vcenter);

      String taskId = UUID.randomUUID().toString();
      Operation op =
          _dbClient.createTaskOpStatus(
              Vcenter.class, vcenter.getId(), taskId, ResourceOperationTypeEnum.DELETE_VCENTER);

      ComputeSystemController controller = getController(ComputeSystemController.class, null);
      controller.detachVcenterStorage(vcenter.getId(), true, taskId);

      auditOp(OperationTypeEnum.DELETE_VCENTER, true, null, vcenter.auditParameters());

      TaskResourceRep taskResourceRep = toTask(vcenter, taskId, op);
      updateTaskTenant(taskResourceRep);

      return taskResourceRep;
    }
  }
  /**
   * Updates one or more of the vCenter attributes. Discovery is initiated after the vCenter is
   * updated.
   *
   * @param id the URN of a ViPR vCenter
   * @param updateParam the parameter that has the attributes to be updated.
   * @prereq none
   * @brief Update vCenter
   * @return the vCenter discovery async task representation.
   */
  @PUT
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.TENANT_ADMIN})
  @Path("/{id}")
  public TaskResourceRep updateVcenter(
      @PathParam("id") URI id,
      VcenterUpdateParam updateParam,
      @QueryParam("validate_connection") @DefaultValue("false") final Boolean validateConnection,
      @QueryParam("discover_vcenter") @DefaultValue("true") final Boolean discoverVcenter) {

    // update the host
    Vcenter vcenter = queryObject(Vcenter.class, id, true);
    validateVcenter(updateParam, vcenter, validateConnection);

    // check the user permissions for this tenant org
    verifyAuthorizedSystemOrTenantOrgUser(
        _permissionsHelper.convertToACLEntries(vcenter.getAcls()));

    populateVcenterData(vcenter, updateParam);
    _dbClient.persistObject(vcenter);
    auditOp(OperationTypeEnum.UPDATE_VCENTER, true, null, vcenter.auditParameters());

    if (discoverVcenter) {
      return doDiscoverVcenter(vcenter);
    } else {
      return createManualReadyTask(vcenter);
    }
  }
  /**
   * Gets the current acl assignments of the requested vCenter.
   *
   * @param vcenterId
   * @return the list of acl assignments of the requested vCenter.
   */
  private ACLAssignments getAclAssignmentsResponse(URI vcenterId) {
    Vcenter vcenter = queryObject(Vcenter.class, vcenterId, true);
    ArgValidator.checkEntity(vcenter, vcenterId, isIdEmbeddedInURL(vcenterId));

    ACLAssignments response = new ACLAssignments();
    response.setAssignments(_permissionsHelper.convertToACLEntries(vcenter.getAcls()));

    return response;
  }
 /**
  * Shows the information for one vCenter server.
  *
  * @param id the URN of a ViPR vCenter
  * @prereq none
  * @brief Show vCenter
  * @return All non-null attributes of the vCenter.
  * @throws DatabaseException when a DB error occurs.
  */
 @GET
 @Path("/{id}")
 @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
 public VcenterRestRep getVcenter(@PathParam("id") URI id) throws DatabaseException {
   Vcenter vcenter = queryObject(Vcenter.class, id, false);
   // check the user permissions for this tenant org
   verifyAuthorizedSystemOrTenantOrgUser(
       _permissionsHelper.convertToACLEntries(vcenter.getAcls()));
   return map(vcenter);
 }
  public void createUpdateVcenterClusterOperation(
      boolean createCluster, URI vcenterId, URI vcenterDataCenterId, URI clusterId, String stepId) {
    VcenterApiClient vcenterApiClient = null;
    try {
      WorkflowStepCompleter.stepExecuting(stepId);

      VcenterDataCenter vcenterDataCenter =
          _dbClient.queryObject(VcenterDataCenter.class, vcenterDataCenterId);
      Cluster cluster = _dbClient.queryObject(Cluster.class, clusterId);
      Vcenter vcenter = _dbClient.queryObject(Vcenter.class, vcenterId);

      vcenterApiClient = new VcenterApiClient(_coordinator.getPropertyInfo());
      vcenterApiClient.setup(vcenter.getIpAddress(), vcenter.getUsername(), vcenter.getPassword());
      String vcenterClusterId = null;
      if (createCluster) {
        _log.info("Create cluster with name " + cluster.getLabel());
        vcenterClusterId =
            vcenterApiClient.createCluster(vcenterDataCenter.getLabel(), cluster.getLabel());
      } else {
        // Use MoRef if present but don't stop if we fail to find cluster based off this because
        // we'll fall back and try on name
        String externalId = cluster.getExternalId();
        if (externalId != null && !externalId.trim().equals("")) {
          _log.info("Update cluster with MoRef " + externalId);
          try {
            vcenterClusterId =
                vcenterApiClient.updateCluster(vcenterDataCenter.getLabel(), externalId);
          } catch (VcenterObjectNotFoundException e) {
            _log.info(
                "Ignore VcenterObjectNotFoundException updateCluster when using MoRef... Try name based search next");
          }
        }
        if (vcenterClusterId == null) {
          _log.info("Update cluster with name " + cluster.getLabel());
          vcenterClusterId =
              vcenterApiClient.updateCluster(vcenterDataCenter.getLabel(), cluster.getLabel());
        }
      }
      _log.info(
          "Successfully created or updated cluster " + cluster.getLabel() + " " + vcenterClusterId);

      cluster.setVcenterDataCenter(vcenterDataCenter.getId());
      cluster.setExternalId(vcenterClusterId);
      _dbClient.updateAndReindexObject(cluster);

      WorkflowStepCompleter.stepSucceded(stepId);
    } catch (Exception e) {
      _log.error("createUpdateVcenterClusterOperation exception " + e);
      WorkflowStepCompleter.stepFailed(
          stepId,
          VcenterControllerException.exceptions.clusterException(e.getLocalizedMessage(), e));
    } finally {
      if (vcenterApiClient != null) vcenterApiClient.destroy();
    }
  }
  // Find a host connected and powered on then refresh it
  public void vcenterClusterSelectHostOperation(
      URI vcenterId, URI vcenterDataCenterId, URI clusterId, URI[] hostUris, String stepId) {
    VcenterApiClient vcenterApiClient = null;
    try {
      WorkflowStepCompleter.stepExecuting(stepId);

      VcenterDataCenter vcenterDataCenter =
          _dbClient.queryObject(VcenterDataCenter.class, vcenterDataCenterId);
      Cluster cluster = _dbClient.queryObject(Cluster.class, clusterId);
      Vcenter vcenter = _dbClient.queryObject(Vcenter.class, vcenterId);
      Collection<Host> hosts = _dbClient.queryObject(Host.class, hostUris);

      vcenterApiClient = new VcenterApiClient(_coordinator.getPropertyInfo());
      vcenterApiClient.setup(vcenter.getIpAddress(), vcenter.getUsername(), vcenter.getPassword());

      Host hostForStorageOperations = null;
      for (Host host : hosts) {
        try {
          vcenterApiClient.checkHostConnectedPoweredOn(
              vcenterDataCenter.getLabel(), cluster.getExternalId(), host.getHostName());
          hostForStorageOperations = host;
          _log.info("Host " + host.getHostName() + " to be used for storage operations");
          break;
        } catch (Exception e) {
          _log.info(
              "Host "
                  + host.getHostName()
                  + " not valid for storage operations due to exception "
                  + e.getLocalizedMessage());
        }
      }
      if (hostForStorageOperations == null) {
        _log.error(
            "No host valid for performing storage operations thus cannot perform datastore operations");
        throw new Exception(
            "No host valid for performing storage operations thus cannot perform datastore operations");
      }
      vcenterApiClient.refreshRescanHostStorage(
          vcenterDataCenter.getLabel(),
          cluster.getExternalId(),
          hostForStorageOperations.getHostName());

      // persist hostForStorageOperations ID in wf data
      _workflowService.storeStepData(stepId, hostForStorageOperations.getId());

      WorkflowStepCompleter.stepSucceded(stepId);
    } catch (Exception e) {
      _log.error("vcenterClusterSelectHostOperation exception " + e);
      WorkflowStepCompleter.stepFailed(
          stepId, VcenterControllerException.exceptions.hostException(e.getLocalizedMessage(), e));
    } finally {
      if (vcenterApiClient != null) vcenterApiClient.destroy();
    }
  }
  /**
   * Validates vCenter user credentials from create or update parameters.
   *
   * @param param either vCenter create or update param.
   * @param vcenter vCenter object.
   */
  private void validateVcenterCredentials(VcenterParam param, Vcenter vcenter) {
    if (StringUtils.isBlank(param.getPassword()) && vcenter != null) {
      param.setPassword(StringUtils.trimToNull(vcenter.getPassword()));
    }

    if (StringUtils.isBlank(param.getUserName()) && vcenter != null) {
      param.setUserName(StringUtils.trimToNull(vcenter.getUsername()));
    }

    ArgValidator.checkFieldNotNull(param.getUserName(), "username");
    ArgValidator.checkFieldNotNull(param.getPassword(), "password");
  }
  public void vcenterClusterCreateDatastoreOperation(
      URI vcenterId,
      URI vcenterDataCenterId,
      URI clusterId,
      URI volumeId,
      String selectHostStepId,
      String stepId) {
    VcenterApiClient vcenterApiClient = null;
    try {
      WorkflowStepCompleter.stepExecuting(stepId);

      URI hostId = (URI) _workflowService.loadStepData(selectHostStepId);
      if (hostId == null) {
        _log.error("Workflow loadStepData on " + selectHostStepId + " is null");
        throw new Exception("Workflow loadStepData on " + selectHostStepId + " is null");
      }

      VcenterDataCenter vcenterDataCenter =
          _dbClient.queryObject(VcenterDataCenter.class, vcenterDataCenterId);
      Cluster cluster = _dbClient.queryObject(Cluster.class, clusterId);
      Vcenter vcenter = _dbClient.queryObject(Vcenter.class, vcenterId);
      Host host = _dbClient.queryObject(Host.class, hostId);
      Volume volume = _dbClient.queryObject(Volume.class, volumeId);

      vcenterApiClient = new VcenterApiClient(_coordinator.getPropertyInfo());
      vcenterApiClient.setup(vcenter.getIpAddress(), vcenter.getUsername(), vcenter.getPassword());
      String key =
          vcenterApiClient.createDatastore(
              vcenterDataCenter.getLabel(),
              cluster.getExternalId(),
              host.getHostName(),
              volume.getWWN(),
              volume.getLabel());
      _log.info("Successfully created or located datastore " + volume.getLabel() + " " + key);

      host.setVcenterDataCenter(vcenterDataCenter.getId());
      _dbClient.updateAndReindexObject(host);

      WorkflowStepCompleter.stepSucceded(stepId);
    } catch (Exception e) {
      _log.error("vcenterClusterCreateDatastoreOperation exception " + e);
      WorkflowStepCompleter.stepFailed(
          stepId, VcenterControllerException.exceptions.hostException(e.getLocalizedMessage(), e));
    } finally {
      if (vcenterApiClient != null) vcenterApiClient.destroy();
    }
  }
  /**
   * Creates a new vCenter. Discovery is initiated after the vCenter is created.
   *
   * @param createParam the parameter that has the attributes of the vCenter to be created.
   * @param validateConnection specifies if the connection to the vCenter to be validated before
   *     creating the vCenter or not. Default value is "false", so connection to the vCenter will
   *     not be validated if it is not specified.
   * @return the vCenter discovery async task.
   */
  @POST
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.TENANT_ADMIN})
  public TaskResourceRep createVcenter(
      VcenterCreateParam createParam,
      @QueryParam("validate_connection") @DefaultValue("false") final Boolean validateConnection) {
    validateVcenter(createParam, null, validateConnection);

    // create and persist the vcenter
    Vcenter vcenter = createNewVcenter(null, createParam);
    vcenter.setRegistrationStatus(DiscoveredDataObject.RegistrationStatus.REGISTERED.toString());
    _dbClient.createObject(vcenter);
    auditOp(OperationTypeEnum.CREATE_VCENTER, true, null, vcenter.auditParameters());

    return doDiscoverVcenter(queryObject(Vcenter.class, vcenter.getId(), true));
  }
    @Override
    public boolean isAccessible(E resrep) {
      boolean ret = false;
      URI id = resrep.getId();

      Vcenter obj = _permissionsHelper.getObjectById(id, Vcenter.class);
      if (obj == null) {
        return false;
      }
      if (obj.getTenant().toString().equals(_user.getTenantId())
          || isSystemAdmin()
          || isSecurityAdmin()) {
        return true;
      }
      ret = isTenantAccessible(obj.getTenant());
      return ret;
    }
  private List<String> getVirtualMachines(
      URI datacenterUri, URI clusterUri, URI hostUri, boolean runningOnly)
      throws InternalException {
    VcenterApiClient vcenterApiClient = null;
    try {
      Host host = _dbClient.queryObject(Host.class, hostUri);
      VcenterDataCenter vcenterDataCenter =
          _dbClient.queryObject(VcenterDataCenter.class, datacenterUri);
      Cluster cluster = _dbClient.queryObject(Cluster.class, clusterUri);
      Vcenter vcenter = _dbClient.queryObject(Vcenter.class, vcenterDataCenter.getVcenter());

      _log.info(
          "Request to get virtual machines for "
              + vcenter.getLabel()
              + "/"
              + vcenterDataCenter.getLabel()
              + "/"
              + cluster.getLabel()
              + "/"
              + host.getHostName());

      vcenterApiClient = new VcenterApiClient(_coordinator.getPropertyInfo());
      vcenterApiClient.setup(vcenter.getIpAddress(), vcenter.getUsername(), vcenter.getPassword());
      return runningOnly
          ? vcenterApiClient.getRunningVirtualMachines(
              vcenterDataCenter.getLabel(), cluster.getExternalId(), host.getHostName())
          : vcenterApiClient.getVirtualMachines(
              vcenterDataCenter.getLabel(), cluster.getExternalId(), host.getHostName());
    } catch (VcenterObjectConnectionException e) {
      throw VcenterControllerException.exceptions.objectConnectionException(
          e.getLocalizedMessage(), e);
    } catch (VcenterObjectNotFoundException e) {
      throw VcenterControllerException.exceptions.objectNotFoundException(
          e.getLocalizedMessage(), e);
    } catch (VcenterServerConnectionException e) {
      throw VcenterControllerException.exceptions.serverConnectionException(
          e.getLocalizedMessage(), e);
    } catch (Exception e) {
      _log.error("getVirtualMachines exception " + e);
      throw VcenterControllerException.exceptions.unexpectedException(e.getLocalizedMessage(), e);
    } finally {
      if (vcenterApiClient != null) vcenterApiClient.destroy();
    }
  }
  /**
   * Check if the vCenter being updated is used by any of its vCenterDataCenters or clusters or
   * hosts or not. This validates only with respect to the tenant that is being removed from the
   * vCenter acls. If the tenant that is getting removed teh vCenter has any exports with the
   * vCenter's vCenterDataCenter or its clusters or hosts.
   *
   * @param vcenter the vCenter being updated.
   * @param changes new acl assignment changes for the vCenter.
   */
  private void checkVcenterUsage(Vcenter vcenter, ACLAssignmentChanges changes) {
    // Make a copy of the vCenter's existing tenant list.
    List<ACLEntry> existingAclEntries = _permissionsHelper.convertToACLEntries(vcenter.getAcls());
    if (CollectionUtils.isEmpty(existingAclEntries)) {
      // If there no existing acl entries for the vCenter
      // there is nothing to validate if it is in user or not.
      _log.debug("vCenter {} does not have any existing acls", vcenter.getLabel());
      return;
    }

    // If there are no tenants to be removed from the vCenter acls,
    // there is nothing to check for usage.
    if (CollectionUtils.isEmpty(changes.getRemove())) {
      _log.debug("There are not acls to remove from vCenter {}", vcenter.getLabel());
      return;
    }

    Set<String> tenantsInUse = new HashSet<String>();

    Set<URI> removingTenants = _permissionsHelper.getUsageURIsFromAclEntries(changes.getRemove());
    Set<URI> existingTenants = _permissionsHelper.getUsageURIsFromAclEntries(existingAclEntries);

    Iterator<URI> removingTenantsIterator = removingTenants.iterator();
    while (removingTenantsIterator.hasNext()) {
      URI removingTenant = removingTenantsIterator.next();
      if (!existingTenants.contains(removingTenant)) {
        continue;
      }

      // Check if vCenter is in use for the removing tenant or not.
      // This checks for all the datacenters of this vcenter that belong to the
      // removing tenant and finds if the datacenter or it clusters or hosts
      // use the exports from the removing tenant or not.
      if (ComputeSystemHelper.isVcenterInUseForTheTenant(
          _dbClient, vcenter.getId(), removingTenant)) {
        TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, removingTenant);
        tenantsInUse.add(tenant.getLabel());
      }
    }

    if (!CollectionUtils.isEmpty(tenantsInUse)) {
      throw APIException.badRequests.cannotRemoveTenant("vCener", vcenter.getLabel(), tenantsInUse);
    }
  }
  /**
   * Validates the create/update vCenter input data
   *
   * @param param the input parameter
   * @param vcenter the vcenter being updated in case of update operation. This parameter must be
   *     null for create operations.
   */
  protected void validateVcenter(VcenterParam param, Vcenter vcenter, Boolean validateConnection) {
    if (vcenter == null
        || (param.findIpAddress() != null
            && !param.findIpAddress().equals(vcenter.getIpAddress()))) {
      checkDuplicateAltId(Vcenter.class, "ipAddress", param.findIpAddress(), "vcenter");
    }
    if (vcenter == null
        || (param.getName() != null && !param.getName().equals(vcenter.getLabel()))) {
      checkDuplicateLabel(Vcenter.class, param.getName(), "vcenter");
    }
    validateVcenterCredentials(param, vcenter);

    if (validateConnection != null && validateConnection == true) {
      String errorMessage = VCenterConnectionValidator.isVCenterConnectionValid(param);
      if (StringUtils.isNotBlank(errorMessage)) {
        throw APIException.badRequests.invalidVCenterConnection(errorMessage);
      }
    }
  }
 /**
  * Creates a new instance of vcenter.
  *
  * @param tenant the vcenter parent tenant organization
  * @param param the input parameter containing the vcenter attributes
  * @return an instance of {@link Vcenter}
  */
 protected Vcenter createNewVcenter(TenantOrg tenant, VcenterParam param) {
   Vcenter vcenter = new Vcenter();
   vcenter.setId(URIUtil.createId(Vcenter.class));
   addVcenterAclIfTenantAdmin(tenant, vcenter);
   populateVcenterData(vcenter, param);
   if (isSystemAdmin()) {
     // Since, the creating user is either SysAdmin make the tenantCreated
     // flag to false.
     vcenter.setTenantCreated(Boolean.FALSE);
   } else {
     // Since the creating user is a TenantAdmin, just make the vCenter
     // as a tenant created resource by default. When the SecAdmin or
     // SysAdmin adds any new tenant then the vCenter will be shared
     // across those tenants.
     _log.debug("Tenant admin creates the vCenter {}", param.getName());
     vcenter.setTenantCreated(Boolean.TRUE);
   }
   return vcenter;
 }
 /**
  * Populate an instance of vcenter with the provided vcenter parameter
  *
  * @param vcenter the vcenter to be populated
  * @param param the parameter that contains the attributes.
  */
 protected void populateVcenterData(Vcenter vcenter, VcenterParam param) {
   vcenter.setLabel(param.getName());
   vcenter.setOsVersion(param.getOsVersion());
   vcenter.setUsername(param.getUserName());
   vcenter.setPassword(param.getPassword());
   vcenter.setIpAddress(param.findIpAddress());
   vcenter.setPortNumber(param.getPortNumber());
   vcenter.setUseSSL(param.getUseSsl());
 }
  /**
   * Creates a manual (fake) vcenter discover task, so that there wont be any vcenter discovery
   * happening because of this task.
   *
   * @param vcenter vcenter to create its manual/fake discovery task.
   * @return returns fake/manual vcenter discovery task.
   */
  private TaskResourceRep createManualReadyTask(Vcenter vcenter) {
    // if not discoverable, manually create a ready task
    Operation op = new Operation();
    op.setResourceType(ResourceOperationTypeEnum.DISCOVER_VCENTER);
    op.ready("Vcenter not discoverable.");

    String taskId = UUID.randomUUID().toString();
    _dbClient.createTaskOpStatus(Host.class, vcenter.getId(), taskId, op);

    return toTask(vcenter, taskId, op);
  }
  /**
   * Detaches storage from the vcenter.
   *
   * @param id the URN of a ViPR vcenter
   * @brief Detach storage from vcenter
   * @return task
   * @throws DatabaseException when a DB error occurs
   */
  @POST
  @Path("/{id}/detach-storage")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.TENANT_ADMIN})
  public TaskResourceRep detachStorage(@PathParam("id") URI id) throws DatabaseException {
    Vcenter vcenter = queryObject(Vcenter.class, id, true);
    ArgValidator.checkEntity(vcenter, id, true);

    checkIfOtherTenantsUsingTheVcenter(vcenter);

    String taskId = UUID.randomUUID().toString();
    Operation op =
        _dbClient.createTaskOpStatus(
            Vcenter.class,
            vcenter.getId(),
            taskId,
            ResourceOperationTypeEnum.DETACH_VCENTER_DATACENTER_STORAGE);
    ComputeSystemController controller = getController(ComputeSystemController.class, null);
    controller.detachVcenterStorage(vcenter.getId(), false, taskId);
    return toTask(vcenter, taskId, op);
  }
  /**
   * Add or remove individual Access Control List entry(s). When the vCenter is created with no
   * shared access (Vcenter.shared = Boolean.FALSE), there cannot be multiple Access Control List
   * Entries associated with this vCenter.
   *
   * @param changes Access Control List assignment changes. Request body must include at least one
   *     add or remove operation
   * @param id the URN of a ViPR Project.
   * @return the vCenter discovery async task.
   */
  @PUT
  @Path("/{id}/acl")
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN})
  public TaskResourceRep updateAclAssignments(
      @PathParam("id") URI id, ACLAssignmentChanges changes) {
    // Make sure the vCenter is a valid one.
    Vcenter vcenter = queryObject(Vcenter.class, id, true);
    ArgValidator.checkEntity(vcenter, id, isIdEmbeddedInURL(id));

    // Validate the acl assignment changes. It is not valid when an
    // acl entry contains more than one privilege or privileges
    // other than USE.
    validateAclAssignments(changes);

    // Make sure that the vCenter with respect to the tenants
    // that we are removing is not in use (means the datacenters
    // and its clusters and hosts with the removing tenant do not
    // have any exports).
    checkVcenterUsage(vcenter, changes);

    _permissionsHelper.updateACLs(
        vcenter, changes, new PermissionsHelper.UsageACLFilter(_permissionsHelper));

    _dbClient.updateAndReindexObject(vcenter);

    auditOp(
        OperationTypeEnum.UPDATE_VCENTER,
        true,
        null,
        vcenter.getId().toString(),
        vcenter.getLabel(),
        changes);

    // Rediscover the vCenter, this will update the updated
    // list of tenants based its latest acls to its datacenters
    // and hosts and clusters.
    return doDiscoverVcenter(queryObject(Vcenter.class, vcenter.getId(), true));
  }
  /**
   * List the vCenter data centers of the vCenter.
   *
   * @param id the URN of a ViPR vCenter
   * @param tid tenant to filter the vCenter data centers. "No-Filter" or "null" indicates, listing
   *     all the vCenters in the system. "Not-Assigned" indicates, list all the vCenters with no
   *     tenants assigned to it.
   * @prereq none
   * @brief List vCenter data centers
   * @return All the list of vCenter data centers.
   * @throws DatabaseException when a DB error occurs.
   */
  @GET
  @Path("/{id}/vcenter-data-centers")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public VcenterDataCenterList getVcenterDataCenters(
      @PathParam("id") URI id, @QueryParam("tenant") URI tid) throws DatabaseException {
    Vcenter vcenter = queryObject(Vcenter.class, id, false);
    ArgValidator.checkEntity(vcenter, id, isIdEmbeddedInURL(id));

    // check the user permissions for this tenant org
    verifyAuthorizedSystemOrTenantOrgUser(
        _permissionsHelper.convertToACLEntries(vcenter.getAcls()));

    URI tenantId;
    if (isSecurityAdmin() || isSystemAdmin()) {
      tenantId = tid;
    } else {
      if (shouldTenantAdminUseTenantParam(tid)) {
        tenantId = tid;
      } else {
        tenantId = URI.create(getUserFromContext().getTenantId());
      }
    }

    _log.debug("Fetching the vCenterDataCenters for the tenant {}", tenantId);

    // get the vcenters
    VcenterDataCenterList list = new VcenterDataCenterList();
    List<NamedElementQueryResultList.NamedElement> elements =
        listChildren(id, VcenterDataCenter.class, DATAOBJECT_NAME_FIELD, "vcenter");

    // Filter the vCenterDataCenters based on the tenant.
    list.setDataCenters(
        map(
            ResourceTypeEnum.VCENTERDATACENTER,
            id,
            filterTenantResourcesByTenant(tenantId, VcenterDataCenter.class, elements)));
    return list;
  }
  /**
   * Vcenter Discovery
   *
   * @param vcenter the Vcenter to be discovered. provided, a new taskId is generated.
   * @return the task used to track the discovery job
   */
  protected TaskResourceRep doDiscoverVcenter(Vcenter vcenter) {
    ComputeSystemController controller = getController(ComputeSystemController.class, "vcenter");
    DiscoveredObjectTaskScheduler scheduler =
        new DiscoveredObjectTaskScheduler(_dbClient, new DiscoverJobExec(controller));
    String taskId = UUID.randomUUID().toString();
    ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1);
    tasks.add(new AsyncTask(Vcenter.class, vcenter.getId(), taskId));

    TaskList taskList = scheduler.scheduleAsyncTasks(tasks);

    TaskResourceRep taskResourceRep = taskList.getTaskList().iterator().next();
    updateTaskTenant(taskResourceRep);

    return taskResourceRep;
  }
  /**
   * List the clusters in a vCenter
   *
   * @param id the URN of a ViPR vCenter
   * @prereq none
   * @brief List vCenter clusters
   * @return The list of clusters of the vCenter.
   * @throws DatabaseException when a DB error occurs.
   */
  @GET
  @Path("/{id}/clusters")
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  public ClusterList getVcenterClusters(@PathParam("id") URI id) throws DatabaseException {
    Vcenter vcenter = queryObject(Vcenter.class, id, false);
    ArgValidator.checkEntity(vcenter, id, isIdEmbeddedInURL(id));

    // check the user permissions for this tenant org
    verifyAuthorizedInTenantOrg(_permissionsHelper.convertToACLEntries(vcenter.getAcls()));

    URI tenantId = URI.create(getUserFromContext().getTenantId());

    List<NamedElementQueryResultList.NamedElement> vCentersDataCenters =
        filterTenantResourcesByTenant(
            tenantId,
            VcenterDataCenter.class,
            listChildren(id, VcenterDataCenter.class, DATAOBJECT_NAME_FIELD, "vcenter"));

    ClusterList list = new ClusterList();
    Iterator<NamedElementQueryResultList.NamedElement> dataCentersIterator =
        vCentersDataCenters.iterator();
    while (dataCentersIterator.hasNext()) {
      NamedElementQueryResultList.NamedElement dataCenterElement = dataCentersIterator.next();
      list.getClusters()
          .addAll(
              map(
                  ResourceTypeEnum.CLUSTER,
                  listChildren(
                      dataCenterElement.getId(),
                      Cluster.class,
                      DATAOBJECT_NAME_FIELD,
                      "vcenterDataCenter")));
    }

    return list;
  }
  private void createOrUpdateVcenterCluster(
      boolean createCluster,
      AsyncTask task,
      URI clusterUri,
      URI[] addHostUris,
      URI[] removeHostUris,
      URI[] volumeUris)
      throws InternalException {
    TaskCompleter completer = null;
    try {
      _log.info(
          "createOrUpdateVcenterCluster "
              + createCluster
              + " "
              + task
              + " "
              + clusterUri
              + " "
              + addHostUris
              + " "
              + removeHostUris);

      if (task == null) {
        _log.error("AsyncTask is null");
        throw new Exception("AsyncTask is null");
      }
      URI vcenterDataCenterId = task._id;
      VcenterDataCenter vcenterDataCenter =
          _dbClient.queryObject(VcenterDataCenter.class, vcenterDataCenterId);

      if (clusterUri == null) {
        _log.error("Cluster URI is null");
        throw new Exception("Cluster URI is null");
      }
      Cluster cluster = _dbClient.queryObject(Cluster.class, clusterUri);

      Vcenter vcenter = _dbClient.queryObject(Vcenter.class, vcenterDataCenter.getVcenter());
      _log.info(
          "Request to create or update cluster "
              + vcenter.getIpAddress()
              + "/"
              + vcenterDataCenter.getLabel()
              + "/"
              + cluster.getLabel());

      Collection<Host> addHosts = new ArrayList<Host>();
      if (addHostUris == null || addHostUris.length == 0) {
        _log.info("Add host URIs is null or empty - Cluster will be created without hosts");
      } else {
        for (URI hostUri : addHostUris) {
          _log.info("createOrUpdateVcenterCluster " + clusterUri + " with add host " + hostUri);
        }
        addHosts = _dbClient.queryObject(Host.class, addHostUris);
      }

      Collection<Host> removeHosts = new ArrayList<Host>();
      if (removeHostUris == null || removeHostUris.length == 0) {
        _log.info("Remove host URIs is null or empty - Cluster will have no removed hosts");
      } else {
        for (URI hostUri : removeHostUris) {
          _log.info("createOrUpdateVcenterCluster " + clusterUri + " with remove host " + hostUri);
        }
        removeHosts = _dbClient.queryObject(Host.class, removeHostUris);
      }

      Collection<Volume> volumes = new ArrayList<Volume>();
      if (volumeUris == null || volumeUris.length == 0) {
        _log.info("Volume URIs is null or empty - Cluster will be created without datastores");
      } else {
        for (URI volumeUri : volumeUris) {
          _log.info("createOrUpdateVcenterCluster " + clusterUri + " with volume " + volumeUri);
        }
        volumes = _dbClient.queryObject(Volume.class, volumeUris);
      }

      completer =
          new VcenterClusterCompleter(
              vcenterDataCenterId,
              task._opId,
              OperationTypeEnum.CREATE_UPDATE_VCENTER_CLUSTER,
              "VCENTER_CONTROLLER");
      Workflow workflow =
          _workflowService.getNewWorkflow(
              this, "CREATE_UPDATE_VCENTER_CLUSTER_WORKFLOW", true, task._opId);
      String clusterStep =
          workflow.createStep(
              "CREATE_UPDATE_VCENTER_CLUSTER_STEP",
              String.format(
                  "vCenter cluster operation in vCenter datacenter %s", vcenterDataCenterId),
              null,
              vcenterDataCenterId,
              vcenterDataCenterId.toString(),
              this.getClass(),
              new Workflow.Method(
                  "createUpdateVcenterClusterOperation",
                  createCluster,
                  vcenter.getId(),
                  vcenterDataCenter.getId(),
                  cluster.getId()),
              null,
              null);

      String lastStep = clusterStep;
      if (removeHosts.size() > 0) {
        for (Host host : removeHosts) {
          String hostStep =
              workflow.createStep(
                  "VCENTER_CLUSTER_REMOVE_HOST",
                  String.format("vCenter cluster remove host operation %s", host.getId()),
                  clusterStep,
                  vcenterDataCenterId,
                  vcenterDataCenterId.toString(),
                  this.getClass(),
                  new Workflow.Method(
                      "vcenterClusterRemoveHostOperation",
                      vcenter.getId(),
                      vcenterDataCenter.getId(),
                      cluster.getId(),
                      host.getId()),
                  null,
                  null);
          lastStep = hostStep; // add host will wait on last of these
        }
      }

      if (addHosts.size() > 0) {
        for (Host host : addHosts) {
          String hostStep =
              workflow.createStep(
                  "VCENTER_CLUSTER_ADD_HOST",
                  String.format("vCenter cluster add host operation %s", host.getId()),
                  lastStep,
                  vcenterDataCenterId,
                  vcenterDataCenterId.toString(),
                  this.getClass(),
                  new Workflow.Method(
                      "vcenterClusterAddHostOperation",
                      vcenter.getId(),
                      vcenterDataCenter.getId(),
                      cluster.getId(),
                      host.getId()),
                  null,
                  null);
        }

        if (volumes.size() > 0) {
          // Once all hosts in cluster select a host to use for shared storage operations
          String selectHostForStorageOperationsStep =
              workflow.createStep(
                  "VCENTER_CLUSTER_SELECT_HOST",
                  String.format(
                      "vCenter cluster select host for storage operations operation vCenter datacenter %s",
                      vcenterDataCenterId),
                  "VCENTER_CLUSTER_ADD_HOST",
                  vcenterDataCenterId,
                  vcenterDataCenterId.toString(),
                  this.getClass(),
                  new Workflow.Method(
                      "vcenterClusterSelectHostOperation",
                      vcenter.getId(),
                      vcenterDataCenter.getId(),
                      cluster.getId(),
                      addHostUris),
                  null,
                  null);

          // Do not run datastore creation in parallel
          // First datastore waits on selectHostForStorageOperationsStep step then next wait on the
          // previous datastore operation
          String volumeStep = null;
          for (Volume volume : volumes) {
            volumeStep =
                workflow.createStep(
                    "VCENTER_CLUSTER_CREATE_DATASTORE",
                    String.format("vCenter cluster create datastore operation %s", volume.getId()),
                    volumeStep == null ? selectHostForStorageOperationsStep : volumeStep,
                    vcenterDataCenterId,
                    vcenterDataCenterId.toString(),
                    this.getClass(),
                    new Workflow.Method(
                        "vcenterClusterCreateDatastoreOperation",
                        vcenter.getId(),
                        vcenterDataCenter.getId(),
                        cluster.getId(),
                        volume.getId(),
                        selectHostForStorageOperationsStep),
                    null,
                    null);
          }
        }
      }

      workflow.executePlan(completer, "Success");
    } catch (Exception e) {
      _log.error("createOrUpdateVcenterCluster caught an exception.", e);
      ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
      completer.error(_dbClient, serviceError);
    }
  }
 @Override
 protected URI getTenantOwner(URI id) {
   Vcenter vcenter = queryObject(Vcenter.class, id, false);
   return vcenter.getTenant();
 }
 /**
  * Check if the other tenants using the vCenter before deleting it. SysAdmin deleting the vCenter
  * is always allowed whereas, if the vCenter is shared with multiple tenants then it cannot be
  * deleted by the Tenant Admin.
  *
  * @param vcenter to be deleted.
  */
 private void checkIfOtherTenantsUsingTheVcenter(Vcenter vcenter) {
   if (!isSystemAdmin() && vcenter.getAcls().size() > 1) {
     throw APIException.forbidden.tenantAdminCannotDeleteVcenter(
         getUserFromContext().getName(), vcenter.getLabel());
   }
 }