@Override
 public StringSetMap configureZoning(
     Map<URI, List<List<StoragePort>>> portGroup,
     Map<String, Map<URI, Set<Initiator>>> initiatorGroup,
     Map<URI, NetworkLite> networkMap,
     StoragePortsAssigner assigner) {
   return VPlexBackEndOrchestratorUtil.configureZoning(
       portGroup, initiatorGroup, networkMap, assigner);
 }
  /**
   * Re-validate the ExportMask
   *
   * <p>This is required to be done as the ExportMask gets updated by reading the cinder export
   * volume response.
   *
   * @param varrayURI
   * @param initiatorPortMap
   * @param mask
   * @param invalidMasks
   * @param directorToInitiatorIds
   * @param idToInitiatorMap
   * @param dbClient
   * @param portWwnToClusterMap
   */
  public void updateZoningMapAndvalidateExportMask(
      URI varrayURI,
      Map<URI, List<StoragePort>> initiatorPortMap,
      URI exportMaskURI,
      Map<String, Set<String>> directorToInitiatorIds,
      Map<String, Initiator> idToInitiatorMap,
      Map<String, String> portWwnToClusterMap,
      StorageSystem vplex,
      StorageSystem array,
      String clusterId,
      String stepId) {

    try {
      WorkflowStepCompleter.stepExecuting(stepId);
      // Export Mask is updated, read it from DB
      ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);

      // First step would be to update the zoning map based on the connectivity
      updateZoningMap(initiatorPortMap, directorToInitiatorIds, exportMask);

      boolean passed =
          VPlexBackEndOrchestratorUtil.validateExportMask(
              varrayURI,
              initiatorPortMap,
              exportMask,
              null,
              directorToInitiatorIds,
              idToInitiatorMap,
              _dbClient,
              portWwnToClusterMap);

      if (!passed) {
        // Mark this mask as inactive, so that we dont pick it in the next iteration
        exportMask.setInactive(Boolean.TRUE);
        _dbClient.persistObject(exportMask);

        _log.error("Export Mask is not suitable for VPLEX to backend storage system");
        WorkflowStepCompleter.stepFailed(
            stepId,
            VPlexApiException.exceptions.couldNotFindValidArrayExportMask(
                vplex.getNativeGuid(), array.getNativeGuid(), clusterId));
        throw VPlexApiException.exceptions.couldNotFindValidArrayExportMask(
            vplex.getNativeGuid(), array.getNativeGuid(), clusterId);
      }

      WorkflowStepCompleter.stepSucceded(stepId);

    } catch (Exception ex) {
      _log.error("Failed to validate export mask for cinder: ", ex);
      VPlexApiException vplexex =
          DeviceControllerExceptions.vplex.failedToValidateExportMask(exportMaskURI.toString(), ex);
      WorkflowStepCompleter.stepFailed(stepId, vplexex);
    }
  }
 /**
  * @param allocator
  * @param candidatePorts
  * @param portsRequested
  * @param nwLite
  * @param varrayURI
  * @return
  */
 private List<StoragePort> allocatePorts(
     StoragePortsAllocator allocator,
     List<StoragePort> candidatePorts,
     int portsRequested,
     NetworkLite nwLite,
     URI varrayURI) {
   return VPlexBackEndOrchestratorUtil.allocatePorts(
       allocator,
       candidatePorts,
       portsRequested,
       nwLite,
       varrayURI,
       simulation,
       _blockScheduler,
       _dbClient);
 }
  @Override
  public StringSetMap configureZoning(
      Map<URI, List<List<StoragePort>>> portGroup,
      Map<String, Map<URI, Set<Initiator>>> initiatorGroup,
      Map<URI, NetworkLite> networkMap,
      StoragePortsAssigner assigner) {
    StringSetMap zoningMap = new StringSetMap();

    // Set up a map to track port usage so that we can use all ports more or less equally.
    Map<StoragePort, Integer> portAUsage = new HashMap<StoragePort, Integer>();
    Map<StoragePort, Integer> portBUsage = new HashMap<StoragePort, Integer>();

    // Iterate through each of the directors, matching each of its initiators
    // with one port.
    for (String director : initiatorGroup.keySet()) {
      for (URI networkURI : initiatorGroup.get(director).keySet()) {
        NetworkLite net = networkMap.get(networkURI);
        for (Initiator initiator : initiatorGroup.get(director).get(networkURI)) {
          // If there are no ports on the initiators network, too bad...
          if (portGroup.get(networkURI) == null) {
            _log.info(String.format("%s -> no ports in network", initiator.getInitiatorPort()));
            continue;
          }
          StringSet ports = new StringSet();
          // Get an A Port
          String aPortName = " ", bPortName = " ";
          StoragePort portA =
              VPlexBackEndOrchestratorUtil.assignPortToInitiator(
                  assigner,
                  portGroup.get(networkURI).iterator().next(),
                  net,
                  initiator,
                  portAUsage,
                  "SP_A");
          if (portA != null) {
            aPortName = portA.getPortName();
            ports.add(portA.getId().toString());
          }
          // Get a B Port
          StoragePort portB =
              VPlexBackEndOrchestratorUtil.assignPortToInitiator(
                  assigner,
                  portGroup.get(networkURI).iterator().next(),
                  net,
                  initiator,
                  portBUsage,
                  "SP_B");
          if (portB != null) {
            bPortName = portB.getPortName();
            ports.add(portB.getId().toString());
          }
          _log.info(
              String.format(
                  "%s %s   %s -> %s  %s",
                  director, net.getLabel(), initiator.getInitiatorPort(), aPortName, bPortName));
          zoningMap.put(initiator.getId().toString(), ports);
        }
      }
    }
    return zoningMap;
  }