/**
  * If any endpoint is used in an active File Export, throws an exception
  *
  * @param endpoints endpoints being added
  * @param varrays endpoints belong to
  *     <p>Assumes endpoint formats have been validated.
  */
 public static void checkNotUsedByActiveFileExport(String endpoint, DbClient dbClient) {
   Network network = NetworkUtil.getEndpointNetwork(endpoint, dbClient);
   if (network != null) {
     Set<String> netVArrayIds = network.getConnectedVirtualArrays();
     if ((netVArrayIds != null) && (!netVArrayIds.isEmpty())) {
       Iterator<String> netVArrayIdsIter = netVArrayIds.iterator();
       while (netVArrayIdsIter.hasNext()) {
         String varrayId = netVArrayIdsIter.next();
         List<FileShare> fileShares =
             CustomQueryUtility.queryActiveResourcesByConstraint(
                 dbClient,
                 FileShare.class,
                 AlternateIdConstraint.Factory.getConstraint(FileShare.class, "varray", varrayId));
         for (FileShare fileShare : fileShares) {
           FSExportMap fsExports = fileShare.getFsExports();
           if (fsExports != null) {
             Iterator<FileExport> it = fsExports.values().iterator();
             while (it.hasNext()) {
               FileExport fileExport = it.next();
               if (fileExport.getClients().contains(endpoint)
                   || fileExport.getStoragePort().contains(endpoint)) {
                 throw APIException.badRequests.endpointsCannotBeUpdatedActiveExport(endpoint);
               }
             }
           }
         }
       }
     }
   }
 }
 @Override
 protected void verifyResults() throws Exception {
   List<URI> networkURIs = _dbClient.queryByType(Network.class, false);
   Iterator<Network> networksIter = _dbClient.queryIterativeObjects(Network.class, networkURIs);
   while (networksIter.hasNext()) {
     Network network = networksIter.next();
     String networkId = network.getId().toString();
     StringSet assignedVArrayIds = network.getAssignedVirtualArrays();
     if (network.getLabel().equals("NetworkWithVarray")) {
       Assert.assertTrue(
           String.format("Network (id=%s) should have an assigned virtual array", networkId),
           ((assignedVArrayIds != null) && (!assignedVArrayIds.isEmpty())));
       int count = 0;
       for (String assignedVArrayId : assignedVArrayIds) {
         Assert.assertTrue(
             "Network has unexpected varray assignment",
             assignedVArrayId.equals(varrayURI.toString()));
         count++;
       }
       Assert.assertTrue("Network has incorrect varray count", count == 1);
     } else {
       Assert.assertTrue(
           String.format("Network (id=%s) should NOT have an assigned virtual array", networkId),
           ((assignedVArrayIds == null) || (assignedVArrayIds.isEmpty())));
     }
   }
 }
 /**
  * Get all the networks belongs to the given network system.
  *
  * @param networkSystem
  * @param allNetworks
  * @return
  */
 private List<Network> getLocalNetworks(NetworkSystem networkSystem, List<Network> allNetworks) {
   List<Network> realNetworks = new ArrayList<Network>();
   for (Network network : allNetworks) {
     if (network.getNetworkSystems() != null
         && network.getNetworkSystems().contains(networkSystem.getId().toString())) {
       realNetworks.add(network);
     }
   }
   return realNetworks;
 }
 /**
  * Get the network by the given fabric ID. Return null if not found.
  *
  * @param networks
  * @param fabricId
  * @return
  */
 private Network getNetworkByNativeId(List<Network> networks, String fabricId) {
   for (Network network : networks) {
     if (network != null
         && network.getNativeId() != null
         && network.getNativeId().equals(fabricId)) {
       return network;
     }
   }
   return null;
 }
 /**
  * Get the connected network systems which are connected by the given transit network.
  *
  * @param transitNetwork
  * @param allNetworks
  * @return
  */
 private Set<String> getConnectedNetworkSystems(String transitNetwork, List<Network> allNetworks) {
   Set<String> connectedNetworkSystems = new HashSet<String>();
   for (Network network : allNetworks) {
     if (network.getNetworkSystems() != null && transitNetwork.equals(network.getNativeId())) {
       for (String networkSystem : network.getNetworkSystems()) {
         connectedNetworkSystems.add(networkSystem);
       }
     }
   }
   return connectedNetworkSystems;
 }
 /**
  * Check if the given network is a remote routed network of the current network system. If it
  * belongs to a connected network system which is not the current network system, it is a remote
  * routed network.
  *
  * @param network The given network.
  * @param currentNetworkSystemId The current network system ID.
  * @param connectedNetworkSystems The connected network systems list.
  * @return true/false
  */
 private boolean isRemoteRoutedNetwork(
     Network network, String currentNetworkSystemId, Set<String> connectedNetworkSystems) {
   if (network.getNetworkSystems() != null) {
     for (String networkSystem : network.getNetworkSystems()) {
       if (networkSystem != currentNetworkSystemId
           && connectedNetworkSystems.contains(networkSystem)) {
         return true;
       }
     }
   }
   return false;
 }
 /**
  * Generate logging output for given network details.
  *
  * @param prefix
  * @param network
  */
 private void dumpRoutedNetworks(String prefix, Network network) {
   StringBuffer sb = new StringBuffer();
   sb.append(prefix + ":");
   sb.append("label = " + network.getLabel() + ", ");
   if (network.getRoutedNetworks() != null) {
     for (String str : network.getRoutedNetworks()) {
       sb.append(", routed = " + str);
     }
   } else {
     sb.append(", routed = null");
   }
   _log.info(sb.toString());
 }
 /** Get all the current networks in the database */
 private List<Network> getCurrentTransportZones() throws Exception {
   List<Network> tzones = new ArrayList<Network>();
   List<URI> uriTransportList = dbClient.queryByType(Network.class, true);
   Iterator<Network> iTZones = dbClient.queryIterativeObjects(Network.class, uriTransportList);
   while (iTZones.hasNext()) {
     Network transportZone = iTZones.next();
     if (transportZone != null
         && Transport.FC.toString().equals(transportZone.getTransportType())) {
       tzones.add(transportZone);
     }
   }
   return tzones;
 }
 /**
  * Finds the network in the list that has this endpoint.
  *
  * @param networks a list of networks
  * @param endpoint the endpoint
  * @parame excludeNetwork - exclude this network from result if provided
  * @return the network that contains the endpoint if found, otherwise null.
  */
 private Network findNetworkForDiscoveredEndPoint(
     Collection<Network> networks, String endpoint, Network excludeNetwork) {
   for (Network network : networks) {
     /*
      * if excludeNetwork not provided, look for first one.
      * Otherwise, ignore the provided network
      */
     if (excludeNetwork == null || !network.getId().equals(excludeNetwork.getId())) {
       if (network.endpointIsDiscovered(endpoint)) {
         return network;
       }
     }
   }
   return null;
 }
 private void saveTransportZone(Network network, boolean newTransportZone) throws IOException {
   if (newTransportZone) {
     dbClient.createObject(network);
     _log.info("Added networks {}", network.getLabel());
     recordTransportZoneEvent(
         network,
         OperationTypeEnum.CREATE_NETWORK.getEvType(true),
         OperationTypeEnum.CREATE_NETWORK.getDescription());
   } else {
     dbClient.updateAndReindexObject(network);
     _log.info("Updated transport zone {}", network.getLabel());
     recordTransportZoneEvent(
         network,
         OperationTypeEnum.UPDATE_NETWORK.getEvType(true),
         OperationTypeEnum.UPDATE_NETWORK.getDescription());
   }
 }
 /**
  * Get the transit network set if there is, otherwise return empty set.
  *
  * @param networkSystem The current discovering network system.
  * @param allNetworks All the existing networks list.
  * @return The transit networks list.
  * @throws Exception The "getFabricIdsMap" may throw exception.
  */
 private Set<String> getTransitNetworks(NetworkSystem networkSystem, List<Network> allNetworks)
     throws Exception {
   Map<String, String> networkWwnIdMap = getDevice().getFabricIdsMap(networkSystem);
   _log.info("getTransitNetworks.networkWwnIdMap = {}", networkWwnIdMap);
   Set<String> transitNetworks = new HashSet<String>();
   for (Entry<String, String> entry : networkWwnIdMap.entrySet()) {
     String currentNetworkId = entry.getValue();
     String currentNetworkWwn = entry.getKey();
     Network currentNetwork = getNetworkByNativeId(allNetworks, currentNetworkId);
     // How to determine it's a transit network: 1. More than one network system have the same
     // network.
     if (currentNetwork != null && currentNetwork.getNetworkSystems().size() > 1) {
       _log.info("Network id={} is a transit VSAN", currentNetworkId);
       transitNetworks.add(currentNetworkId);
     } else {
       _log.info("Network id={} is NOT a transit VSAN", currentNetworkId);
     }
   }
   return transitNetworks;
 }
 /**
  * Remove the transport zone for a given network system. This typically means to dis-associated it
  * unless this is the last network system associated with the transport zone. In this case, the
  * transport zone will be deleted if:
  *
  * <ul>
  *   <li>It was discovered
  *   <li>It does not have any user-created ports
  *   <li>It does not have any registered ports
  * </ul>
  *
  * @param tzone
  * @param uri
  * @throws IOException
  */
 public List<String> removeNetworkSystemTransportZone(Network tzone, String uri)
     throws IOException {
   tzone.removeNetworkSystems(Collections.singletonList(uri)); // dis-associate
   // list of end points getting deleted
   ArrayList<String> toRemove = new ArrayList<String>();
   if (tzone.getNetworkSystems().isEmpty()) { // if this is the last network system
     List<String> userCreatedEndPoints = TransportZoneReconciler.getUserCreatedEndPoints(tzone);
     if (userCreatedEndPoints.isEmpty()
         && !tzone.assignedToVarray()) { // delete only if not modified by a user
       _log.info("Removing network {}", tzone.getLabel());
       toRemove.addAll(tzone.retrieveEndpoints());
       NetworkAssociationHelper.handleEndpointsRemoved(tzone, toRemove, dbClient, _coordinator);
       dbClient.markForDeletion(tzone);
       recordTransportZoneEvent(
           tzone,
           OperationTypeEnum.DELETE_NETWORK.getEvType(true),
           OperationTypeEnum.DELETE_NETWORK.getDescription());
     } else {
       _log.info(
           "Network {} is changed by the user and will "
               + "not be removed. Discovered end points will be removed.",
           tzone.getLabel());
       for (String pt : tzone.retrieveEndpoints()) {
         if (!userCreatedEndPoints.contains(pt)) {
           toRemove.add(pt);
         }
       }
       tzone.removeEndpoints(toRemove);
       NetworkAssociationHelper.handleEndpointsRemoved(tzone, toRemove, dbClient, _coordinator);
       _log.info("Discovered endpoints removed {}", toRemove.toArray());
       dbClient.persistObject(tzone);
       recordTransportZoneEvent(
           tzone,
           OperationTypeEnum.UPDATE_NETWORK.getEvType(true),
           OperationTypeEnum.UPDATE_NETWORK.getDescription());
     }
   } else {
     _log.info("Removing network {} from network system {}", tzone.getLabel(), uri);
     dbClient.persistObject(tzone);
     recordTransportZoneEvent(
         tzone,
         OperationTypeEnum.UPDATE_NETWORK.getEvType(true),
         OperationTypeEnum.UPDATE_NETWORK.getDescription());
   }
   return toRemove;
 }
 /**
  * Get the network the endpoint is associated with if any
  *
  * @param endpoint
  * @param dbClient
  * @return a reference to a network Assumes endpoint formats have been validated.
  */
 public static Network getEndpointNetwork(String endpoint, DbClient dbClient) {
   _log.debug("Finding network for endpoint {}", endpoint);
   URIQueryResultList networkList = new URIQueryResultList();
   Iterator<URI> iterator;
   URI networkUri = null;
   Network network;
   dbClient.queryByConstraint(
       AlternateIdConstraint.Factory.getEndpointNetworkConstraint(endpoint), networkList);
   iterator = networkList.iterator();
   while (iterator.hasNext()) {
     networkUri = iterator.next();
     network = dbClient.queryObject(Network.class, networkUri);
     if (network != null && network.getInactive() == false) {
       _log.info("network {} for endpoint {} was found", networkUri, endpoint);
       return network;
     } else {
       _log.info("network {} for endpoint {} was deleted or is inactive", networkUri, endpoint);
     }
   }
   _log.info("network could not be found for endpoint {}", endpoint);
   return null;
 }
 private void handleEndpointsAdded(Network tzone, Collection<String> endpoints)
     throws IOException {
   // find if the endpoints exit in some old transport zone
   Map<String, Network> transportZoneMap =
       NetworkAssociationHelper.getNetworksMap(endpoints, dbClient);
   if (!transportZoneMap.isEmpty()) {
     _log.info("Added endpoints {} to transport zone {}", endpoints.toArray(), tzone.getLabel());
     // before we add the endpoints, they need to be removed from their old transport zones
     NetworkAssociationHelper.handleRemoveFromOldNetworks(
         transportZoneMap, tzone, dbClient, _coordinator);
   }
   // now, add the the endpoints
   NetworkAssociationHelper.handleEndpointsAdded(tzone, endpoints, dbClient, _coordinator);
 }
 /**
  * Update all the networks "routedNetworks" field by adding the routed networks list according to
  * the given transit network, including both "localNetworks" and "remoteRoutedNetworks".
  *
  * @param networkSystem
  * @param connectedNetworkSystems
  * @param allNetworks
  */
 private void updateRoutedNetworksForTransitNetwork(
     NetworkSystem networkSystem, Set<String> connectedNetworkSystems, List<Network> allNetworks) {
   // 1. Get localNetworks, remoteRoutedNetworks and routedNetworks. With transit network, both the
   // local
   // networks and the remote routed networks are routed.
   List<Network> localNetworks = getLocalNetworks(networkSystem, allNetworks);
   for (Network network : localNetworks) {
     dumpRoutedNetworks("localNetwork = ", network);
   }
   List<Network> remoteRoutedNetworks =
       this.getRemoteRoutedNetworks(
           networkSystem.getId().toString(), connectedNetworkSystems, allNetworks);
   for (Network network : remoteRoutedNetworks) {
     dumpRoutedNetworks("remoteRoutedNetworks = ", network);
   }
   List<Network> routedNetworks = new ArrayList<Network>(localNetworks);
   routedNetworks.addAll(remoteRoutedNetworks);
   for (Network network : routedNetworks) {
     dumpRoutedNetworks("routedNetworks = ", network);
   }
   // 2. Update each local network by setting the routed networks.
   for (Network currentNetwork : localNetworks) {
     boolean modified = false;
     StringSet networkSet = currentNetwork.getRoutedNetworks();
     _log.info("NetworkDiscoveryWorker handling routed network, existing: {}", networkSet);
     if (networkSet == null) {
       networkSet = new StringSet();
     }
     for (Network routedNetwork : routedNetworks) {
       if (!networkSet.contains(routedNetwork.getId().toString())
           && !routedNetwork.getId().equals(currentNetwork.getId())) {
         networkSet.add(routedNetwork.getId().toString());
         modified = true;
       }
     }
     _log.info("NetworkDiscoveryWorker handling routed network, updated: {}", networkSet);
     if (modified) {
       currentNetwork.setRoutedNetworks(networkSet);
       dumpRoutedNetworks("update network=", currentNetwork);
       dbClient.updateObject(currentNetwork);
     }
   }
 }
  @SuppressWarnings("deprecation")
  @Override
  protected void prepareData() throws Exception {

    // Create a virtual array.
    VirtualArray varray = new VirtualArray();
    varrayURI = URIUtil.createId(VirtualArray.class);
    varray.setId(varrayURI);
    _dbClient.createObject(varray);

    // Create a network and set the virtual array.
    Network network = new Network();
    network.setId(URIUtil.createId(Network.class));
    network.setLabel("NetworkWithVarray");
    network.setVirtualArray(varrayURI);
    _dbClient.createObject(network);

    // Create another network without a virtual array.
    network = new Network();
    network.setId(URIUtil.createId(Network.class));
    network.setLabel("NetworkWithoutVArray");
    _dbClient.createObject(network);
  }
 /**
  * Parses the WWN from the network's Native GUID
  *
  * @param network the network
  * @return the network WWN
  */
 public static String getNetworkWwn(Network network) {
   return parseNetworkWwn(network.getNativeGuid());
 }
  /**
   * Given the updated list of end points for one network system, this function will update the
   * transport zones. Require lock when reconciles vsan in fabrics that are linked through ISL.
   * Without locking, multiple VSANs could have same native gui id within the same fabric.
   *
   * @param networkSystem the network system
   * @param routedEndpoints IN/OUT parameter to get the routed endpoints map of
   *     Fabric-WWN-to-endpoints-WWN
   * @throws ControllerException
   */
  private void reconcileTransportZones(
      NetworkSystem networkSystem, Map<String, Set<String>> routedEndpoints)
      throws ControllerException {

    _log.info("reconcileTransportZones for networkSystem {}", networkSystem.getId());
    ControllerServiceImpl.Lock lock =
        ControllerServiceImpl.Lock.getLock(ControllerServiceImpl.DISCOVERY_RECONCILE_TZ);
    try {
      _log.debug(
          "Acquiring lock to reconcile transport zone for networkSystem {}", networkSystem.getId());
      lock.acquire();
      _log.info(
          "Acquired lock to reconcile transport zone for networkSystem {}", networkSystem.getId());

      // get the network system's connections from the database
      Iterator<FCEndpoint> iNewEndPoints = getNetworkSystemEndPoints(networkSystem);
      // get all the transport zones we have in the DB
      List<Network> oldTransportZones = getCurrentTransportZones();
      _log.info("Found {} existing transport zones", oldTransportZones.size());
      // get the fabrics that exist on the network system
      Map<String, String> fabricIdsMap = getDevice().getFabricIdsMap(networkSystem);
      // get the list of fabrics added, removed, changed
      TransportZoneReconciler reconciler = new TransportZoneReconciler();
      TransportZoneReconciler.Results results =
          reconciler.reconcile(networkSystem, iNewEndPoints, fabricIdsMap, oldTransportZones);
      String networkSystemUri = networkSystem.getId().toString();
      for (Network tzone : results.getRemoved()) {
        List<String> removedEps = removeNetworkSystemTransportZone(tzone, networkSystemUri);
        _log.info(
            "Removed network {} which removed discovered endpoints {}",
            tzone.getNativeGuid(),
            removedEps);
      }
      for (Network tzone : results.getAdded()) {
        handleEndpointsAdded(tzone, tzone.retrieveEndpoints());
        saveTransportZone(tzone, true);
      }
      for (Network tzone : results.getModified()) {
        if (results.getRemovedEndPoints().get(tzone) != null) {
          NetworkAssociationHelper.handleEndpointsRemoved(
              tzone, results.getRemovedEndPoints().get(tzone), dbClient, _coordinator);
        }
        if (results.getAddedEndPoints().get(tzone) != null) {
          handleEndpointsAdded(tzone, results.getAddedEndPoints().get(tzone));
        }
        saveTransportZone(tzone, false);
      }
      // update routed networks for routed and modified networks
      updateRoutedNetworks(networkSystem, results.getAddedAndModified(), routedEndpoints);
    } catch (Exception ex) {
      throw NetworkDeviceControllerException.exceptions.reconcileTransportZonesFailedExc(
          new Date().toString(), ex);
    } finally {
      try {
        _log.debug(
            "Releasing reconcile transport zone lock for networkSystem {}", networkSystem.getId());
        lock.release();
        _log.info(
            "Released reconcile transport zone lock for networkSystem {}", networkSystem.getId());
      } catch (Exception e) {
        _log.error(
            "Failed to release  Lock while reconcile transport zone for network {} -->{}",
            networkSystem.getId(),
            e.getMessage());
      }
    }
  }
  /**
   * Looks in the topology view for endpoints that accessible by routing
   *
   * @param networkSystem the network system being refreshed
   * @param updatedNetworks the networks that require updating
   * @param routedEndpoints the routed endpoints map of Fabric-WWN-to-endpoints-WWN
   * @throws Exception
   */
  private void updateRoutedNetworks(
      NetworkSystem networkSystem,
      List<Network> updatedNetworks,
      Map<String, Set<String>> routedEndpoints)
      throws Exception {
    // for each network, get the list of routed ports and locate them in other networks
    StringSet routedNetworks = null;
    Network routedNetwork = null;

    // get the current networks from the database
    Map<URI, Network> allNetworks = DataObjectUtils.toMap(getCurrentTransportZones());
    for (Network network : updatedNetworks) {
      // if this network has any routed endpoints
      Set<String> netRoutedEndpoints = routedEndpoints.get(NetworkUtil.getNetworkWwn(network));
      if (netRoutedEndpoints == null || netRoutedEndpoints.isEmpty()) {
        _log.debug("No routed endpoint in network {}", network.getNativeGuid());
        network.setRoutedNetworks(null);
      } else {
        _log.info(
            "Found {} routed endpoint in network {}", netRoutedEndpoints, network.getNativeGuid());
        routedNetworks = new StringSet();
        for (String endpoint : netRoutedEndpoints) {
          // find the source network of the routed endpoint
          routedNetwork = findNetworkForDiscoveredEndPoint(allNetworks.values(), endpoint, network);
          if (routedNetwork != null) { // it is possible we did not discover the source
            routedNetworks.add(routedNetwork.getId().toString());
          }
        }
        network.setRoutedNetworks(routedNetworks);
      }
      dbClient.updateAndReindexObject(network);
      _log.info("Updated routed networks for {} to {}", network.getNativeGuid(), routedNetworks);
    }
    // clean up transit networks from any one-way associations.
    // Transit networks will show any endpoints routed thru them
    // which may cause one-way associations in the routedNetworks.
    // For example if network A has ep1 and B has ep2 and there is
    // a routed zone between A and B, the transit network C will
    // reports ep1 and ep2 but there is not actual routing between
    // C and A or C and B, so we want to remove these associations.
    for (URI id : allNetworks.keySet()) {
      Network net = allNetworks.get(id);
      boolean updated = false;
      if (net.getRoutedNetworks() != null) {
        routedNetworks = new StringSet(net.getRoutedNetworks());
        // for each network this network is pointing to
        for (String strUri : net.getRoutedNetworks()) {
          // get the opposite network
          Network opNet = allNetworks.get(URI.create(strUri));
          if (opNet != null // it is possible this network is getting removed - the next discovery
              // cleans up
              && opNet.getRoutedNetworks()
                  != null // check for null in case the other network routed eps are not yet visible
              && !opNet
                  .getRoutedNetworks()
                  .contains(net.getId().toString())) { // if the opposite network is not seeing this
            // one
            // remove this association because the opposite network is does not have the matching
            // association
            routedNetworks.remove(opNet.getId().toString());
            updated = true;
          }
        }
        if (updated) {
          _log.info("Reconciled routed networks for {} to {}", net.getNativeGuid(), routedNetworks);
          net.setRoutedNetworks(routedNetworks);
          dbClient.updateAndReindexObject(net);
        }
      }
    }
    for (Network network : allNetworks.values()) {
      NetworkAssociationHelper.setNetworkConnectedVirtualArrays(network, false, dbClient);
    }
    /*
     * COP-23266, COP-20698: Fix the problem that ViPR could not create IVR zone between VSANs routed by
     * transit VSAN(network), the "routedNetwork" field of "Network" data object should be updated based
     * on the transit network(s) if there is.
     */
    this.updateTransitRoutedNetworks(networkSystem);
  }