@Override
  public void deleteSingleVolumeSnapshot(
      StorageSystem storage, URI snapshot, TaskCompleter taskCompleter)
      throws DeviceControllerException {

    try {
      BlockSnapshot snap = _dbClient.queryObject(BlockSnapshot.class, snapshot);
      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeLunSnap lunSnap = apiClient.getLunSnapshot(snap.getNativeId());
      if (lunSnap != null) {
        VNXeCommandJob job = apiClient.deleteLunSnap(lunSnap.getId());
        if (job != null) {
          ControllerServiceImpl.enqueueJob(
              new QueueJob(
                  new VNXeBlockDeleteSnapshotJob(job.getId(), storage.getId(), taskCompleter)));
        }
      } else {
        // Perhaps, it's already been deleted or was deleted on the array.
        // In that case, we'll just say all is well, so that this operation
        // is idempotent.
        snap.setInactive(true);
        snap.setIsSyncActive(false);
        _dbClient.updateObject(snap);
        taskCompleter.ready(_dbClient);
      }
    } catch (VNXeException e) {
      _log.error("Delete volume snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);
    } catch (Exception ex) {
      _log.error("Delete volume snapshot got the exception", ex);
      ServiceError error = DeviceControllerErrors.vnxe.jobFailed("DeleteSnapshot", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }
  @Override
  public void deleteGroupSnapshots(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter)
      throws DeviceControllerException {
    try {
      List<BlockSnapshot> snapshots =
          _dbClient.queryObject(BlockSnapshot.class, Arrays.asList(snapshot));
      BlockSnapshot snapshotObj = snapshots.get(0);

      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeLunGroupSnap lunGroupSnap =
          apiClient.getLunGroupSnapshot(snapshotObj.getReplicationGroupInstance());
      if (lunGroupSnap != null) {
        VNXeCommandJob job = apiClient.deleteLunGroupSnap(lunGroupSnap.getId());
        if (job != null) {
          ControllerServiceImpl.enqueueJob(
              new QueueJob(
                  new VNXeBlockDeleteSnapshotJob(job.getId(), storage.getId(), taskCompleter)));
        } else {
          // Should not take this path, but treat as an error if we do
          // happen to get a null job due to some error in the client.
          _log.error("Unexpected null job from VNXe client call to delete group snapshot.");
          ServiceCoded sc =
              DeviceControllerExceptions.vnxe.nullJobForDeleteGroupSnapshot(
                  snapshotObj.forDisplay(), snapshotObj.getReplicationGroupInstance());
          taskCompleter.error(_dbClient, sc);
        }
      } else {
        // Treat as in the single volume snapshot case and presume
        // the group snapshot has already been deleted.
        List<BlockSnapshot> grpSnapshots =
            ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshotObj, _dbClient);
        for (BlockSnapshot grpSnapshot : grpSnapshots) {
          grpSnapshot.setInactive(true);
          grpSnapshot.setIsSyncActive(false);
        }
        _dbClient.updateObject(grpSnapshots);
        taskCompleter.ready(_dbClient);
      }
    } catch (VNXeException e) {
      _log.error("Delete group snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);
    } catch (Exception ex) {
      _log.error("Delete group snapshot got the exception", ex);
      ServiceError error =
          DeviceControllerErrors.vnxe.jobFailed("DeletGroupSnapshot", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }
  @Override
  public void createGroupSnapshots(
      StorageSystem storage,
      List<URI> snapshotList,
      Boolean createInactive,
      Boolean readOnly,
      TaskCompleter taskCompleter)
      throws DeviceControllerException {
    try {
      URI snapshot = snapshotList.get(0);
      BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);

      Volume volume = _dbClient.queryObject(Volume.class, snapshotObj.getParent());
      TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, volume.getTenant().getURI());
      String tenantName = tenant.getLabel();
      String snapLabelToUse =
          _nameGenerator.generate(
              tenantName,
              snapshotObj.getLabel(),
              snapshot.toString(),
              '-',
              SmisConstants.MAX_SNAPSHOT_NAME_LENGTH);
      String groupName = getConsistencyGroupName(snapshotObj);
      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeCommandJob job = apiClient.createLunGroupSnap(groupName, snapLabelToUse);
      if (job != null) {
        ControllerServiceImpl.enqueueJob(
            new QueueJob(
                new VNXeBlockCreateCGSnapshotJob(
                    job.getId(), storage.getId(), !createInactive, taskCompleter)));
      }

    } catch (VNXeException e) {
      _log.error("Create volume snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);

    } catch (Exception ex) {
      _log.error("Create volume snapshot got the exception", ex);
      ServiceError error =
          DeviceControllerErrors.vnxe.jobFailed("CreateCGSnapshot", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }
  @Override
  public void restoreGroupSnapshots(
      StorageSystem storage, URI volume, URI snapshot, TaskCompleter taskCompleter)
      throws DeviceControllerException {

    try {
      BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);

      VNXeApiClient apiClient = getVnxeClient(storage);
      VNXeLunGroupSnap lunGroupSnap =
          apiClient.getLunGroupSnapshot(snapshotObj.getReplicationGroupInstance());
      // Error out if the snapshot is attached
      if (lunGroupSnap.getIsAttached()) {
        _log.error(
            "Snapshot {})is attached and cannot be used for restore", snapshotObj.getLabel());
        ServiceError error =
            DeviceControllerErrors.vnxe.cannotRestoreAttachedSnapshot(snapshot.toString());
        taskCompleter.error(_dbClient, error);
      }
      VNXeCommandJob job = apiClient.restoreLunGroupSnap(lunGroupSnap.getId());
      if (job != null) {
        ControllerServiceImpl.enqueueJob(
            new QueueJob(
                new VNXeBlockRestoreSnapshotJob(job.getId(), storage.getId(), taskCompleter)));
      }

    } catch (VNXeException e) {
      _log.error("Restore group snapshot got the exception", e);
      taskCompleter.error(_dbClient, e);

    } catch (Exception ex) {
      _log.error("Restore group snapshot got the exception", ex);
      ServiceError error =
          DeviceControllerErrors.vnxe.jobFailed("RestoreSnapshotJob", ex.getMessage());
      taskCompleter.error(_dbClient, error);
    }
  }