/**
   * Get all predefined all floating IPs defined in cartridge definition.
   *
   * @param array of {@link NetworkInterface}
   * @return list of predefined floating IPs
   */
  public List<String> getAllPredefinedFloatingIPs(NetworkInterface[] networkInterfaces) {
    String nwInterfacesNullMsg = "Input NetworkInterface array cannot be null";
    assertNotNull(networkInterfaces, nwInterfacesNullMsg);

    List<String> allPredefinedFloatingIPs = new ArrayList<String>();
    for (NetworkInterface networkInterface : networkInterfaces) {
      // if no floating networks defined, skip it
      if (null == networkInterface.getFloatingNetworks()) {
        continue;
      }
      FloatingNetwork[] floatingNetworks =
          networkInterface.getFloatingNetworks().getFloatingNetworks();
      if (floatingNetworks == null || floatingNetworks.length == 0) {
        continue;
      }

      for (FloatingNetwork floatingNetwork : floatingNetworks) {
        String floatingIP = floatingNetwork.getFloatingIP();
        // we are giving more priority to network uuid over fixed floating IPs
        // so if both network uuid and floating IPs defined, we are not going to assign those
        // floating IPs
        // so these can be assigned to some other interfaces
        // hence excluding from predefined floating IPs list
        String networkUuid = floatingNetwork.getNetworkUuid();
        if (networkUuid == null || networkUuid.isEmpty()) {
          if (floatingIP != null && InetAddresses.isInetAddress(floatingIP)) {
            allPredefinedFloatingIPs.add(floatingIP);
          }
        }
      }
    }
    return allPredefinedFloatingIPs;
  }
  @Override
  public List<String> associateAddresses(NodeMetadata node) {

    assertNotNull(node, "Node cannot be null");

    if (null == neutronApi || null == portApi || null == floatingIPApi) {
      buildNeutronApi();
    }

    // internal network uuid to floating networks map, as defined in cartridge definition
    Map<String, List<FloatingNetwork>> networkUuidToFloatingNetworksMap =
        getNetworkUuidToFloatingNetworksMap(iaasProvider.getNetworkInterfaces());

    // private IP to floating networks map, as defined in cartridge definition
    Map<String, List<FloatingNetwork>> fixedIPToFloatingNetworksMap =
        getFixedIPToFloatingNetworksMap(iaasProvider.getNetworkInterfaces());

    // list of IPs allocated to this node
    List<String> associatedFloatingIPs = new ArrayList<String>();

    // wait until node gets private IPs
    while (node.getPrivateAddresses() == null) {
      CloudControllerUtil.sleep(1000);
    }

    // loop through all the fixed IPs of this node
    // and see whether we need to assign floating IP to each according to the cartridge deployment
    for (String privateIPOfTheNode : node.getPrivateAddresses()) {
      Port portOfTheFixedIP = getPortByFixedIP(privateIPOfTheNode);
      if (null == portOfTheFixedIP) {
        // we can't assign floating IP if port is null
        // it can't happen, a fixed/private IP can't live without a port
        // but doing a null check to be on the safe side
        if (log.isDebugEnabled()) {
          String msg = String.format("Port not found for fixed IP %s", privateIPOfTheNode);
          log.debug(msg);
        }
        continue;
      }
      // get list of floating networks associated with each network interfaces (refer cartridge
      // definition)
      List<FloatingNetwork> floatingNetworks =
          networkUuidToFloatingNetworksMap.get(portOfTheFixedIP.getNetworkId());
      // if no floating networks is defined for a network interface, no need to assign any floating
      // IPs, skip the current iteration
      if (null == floatingNetworks || floatingNetworks.isEmpty()) {
        // since no floating networks found in networkUuidToFloatingNetworksMap,
        // we will search in fixedIPToFloatingNetworksMap
        floatingNetworks = fixedIPToFloatingNetworksMap.get(privateIPOfTheNode);
        if (null == floatingNetworks || floatingNetworks.isEmpty()) {
          if (log.isDebugEnabled()) {
            String msg =
                String.format(
                    "No floating networks defined for the network interface %s",
                    portOfTheFixedIP.getNetworkId());
            log.debug(msg);
          }
        }
        continue;
      }
      // if floating networks defined for a network interface, assign one floating IP from each
      // floating network
      for (FloatingNetwork floatingNetwork : floatingNetworks) {
        FloatingIP allocatedFloatingIP = null;
        if (floatingNetwork.getNetworkUuid() != null
            && !floatingNetwork.getNetworkUuid().isEmpty()) {
          allocatedFloatingIP =
              assignFloatingIP(portOfTheFixedIP, floatingNetwork.getNetworkUuid());
        } else if (floatingNetwork.getFloatingIP() != null
            && !floatingNetwork.getFloatingIP().isEmpty()) {
          allocatedFloatingIP =
              assignPredefinedFloatingIP(portOfTheFixedIP, floatingNetwork.getFloatingIP());
        } else {
          String msg =
              String.format(
                  "Neither floating network uuid or floating IP defined for the floating network %s",
                  floatingNetwork.getName());
          log.error(msg);
          throw new CloudControllerException(msg);
        }

        String allocatedFloatingIPNullMsg =
            String.format(
                "Error occured while assigning floating IP. "
                    + "Please check whether the floating network %s can be reached from the fixed IP range",
                floatingNetwork.getNetworkUuid());
        assertNotNull(allocatedFloatingIP, allocatedFloatingIPNullMsg);

        String allocatedFloatingIPAddressNullOrEmptyMsg =
            String.format(
                "Error occured while assigning floating IP. "
                    + "Please check whether the floating network %s can be reached from the fixed IP range",
                floatingNetwork.getNetworkUuid());
        assertNotNullAndNotEmpty(
            allocatedFloatingIP.getFloatingIpAddress(), allocatedFloatingIPAddressNullOrEmptyMsg);

        associatedFloatingIPs.add(allocatedFloatingIP.getFloatingIpAddress());
      }
    }
    return associatedFloatingIPs;
  }