Example #1
0
  /**
   * Add additional state-update to record information about a door.
   *
   * @param update the StateUpdate we are to add metrics to.
   * @param pathToDoor a StatePath under which we are to add data.
   * @param info the information about the door.
   * @param lifetime the duration, in seconds, for this information
   */
  private void addDoorInfo(
      StateUpdate update, StatePath pathToDoor, LoginBrokerInfo info, long lifetime) {
    StatePath pathToProtocol = pathToDoor.newChild("protocol");

    conditionalAddString(update, pathToProtocol, "engine", info.getProtocolEngine(), lifetime);
    conditionalAddString(update, pathToProtocol, "family", info.getProtocolFamily(), lifetime);
    conditionalAddString(update, pathToProtocol, "version", info.getProtocolVersion(), lifetime);
    conditionalAddString(update, pathToProtocol, "root", info.getRoot(), lifetime);

    update.appendUpdate(
        pathToDoor.newChild("load"), new FloatingPointStateValue(info.getLoad(), lifetime));
    update.appendUpdate(
        pathToDoor.newChild("port"), new IntegerStateValue(info.getPort(), lifetime));
    update.appendUpdate(
        pathToDoor.newChild("cell"), new StringStateValue(info.getCellName(), lifetime));
    update.appendUpdate(
        pathToDoor.newChild("domain"), new StringStateValue(info.getDomainName(), lifetime));
    update.appendUpdate(
        pathToDoor.newChild("update-time"), new IntegerStateValue(info.getUpdateTime(), lifetime));

    info.getAddresses()
        .stream()
        .forEach(i -> addInterfaceInfo(update, pathToDoor.newChild("interfaces"), i, lifetime));

    update.appendUpdateCollection(pathToDoor.newChild("tags"), info.getTags(), lifetime);
  }
  /**
   * Build a StatePath for a given VO to the summary of that VO's SRM reservations; for example,
   * <code>summary.reservations.by-vo.atlas</code>
   *
   * @param voName The name of the VO
   * @return a StatePath pointing to the "by-description" part of this VO's reservation summary.
   */
  private static StatePath buildVoPath(String voName) {
    if (voName == null) {
      throw new IllegalArgumentException("voName is null");
    }

    return RESERVATIONS_BASE_PATH.newChild(voName);
  }
 /**
  * Purge all IDs that are not present in this ReservationSummaryInfo but are missing from a new
  * version of ReservationSummaryInfo
  *
  * @param update the StateUpdate to add adjust.
  * @param basePath the base path of the IDs
  * @param newInfo the new version of this ReservationSummaryInfo
  */
 public void purgeMissingIds(
     StateUpdate update, StatePath basePath, ReservationSummaryInfo newInfo) {
   for (String id : _ids) {
     if (!newInfo.hasId(id)) {
       update.purgeUnder(basePath.newChild(id));
     }
   }
 }
Example #4
0
  /**
   * Add a standardised amount of information about an interface. This is in the form:
   *
   * <pre>
   *     [interfaces]
   *       |
   *       |
   *       +--[ id ] (branch)
   *       |   |
   *       |   +-- "order"  (integer metric: 1 .. 2 ..)
   *       |   +-- "FQDN" (string metric: the host's FQDN, as presented by the door)
   *       |   +-- "address" (string metric: the host's address; e.g., "127.0.0.1")
   *       |   +-- "address-type"    (string metric: "IPv4", "IPv6" or "unknown")
   *       |   +-- "scope"    (string metric: "IPv4", "IPv6" or "unknown")
   *       |
   * </pre>
   *
   * @param update The StateUpdate to append the new metrics.
   * @param parentPath the path that the id branch will be added.
   * @param lifetime how long the created metrics should last.
   */
  private void addInterfaceInfo(
      StateUpdate update, StatePath parentPath, InetAddress address, long lifetime) {
    StatePath pathToInterfaceBranch = parentPath.newChild(address.getHostAddress());

    String hostName = address.getHostName();
    update.appendUpdate(
        pathToInterfaceBranch.newChild("FQDN"), new StringStateValue(hostName, lifetime));

    String urlName = (isInetAddress(hostName)) ? toUriString(address) : hostName;
    update.appendUpdate(
        pathToInterfaceBranch.newChild("url-name"), new StringStateValue(urlName, lifetime));

    update.appendUpdate(
        pathToInterfaceBranch.newChild("address"),
        new StringStateValue(address.getHostAddress(), lifetime));
    update.appendUpdate(
        pathToInterfaceBranch.newChild("address-type"),
        new StringStateValue(
            (address instanceof Inet4Address)
                ? "IPv4"
                : (address instanceof Inet6Address) ? "IPv6" : "unknown",
            lifetime));
    update.appendUpdate(
        pathToInterfaceBranch.newChild("scope"),
        new StringStateValue(NetworkUtils.InetAddressScope.of(address).toString().toLowerCase()));
  }
Example #5
0
 public void messageArrived(LoginBrokerInfo info) {
   StateUpdate update = new StateUpdate();
   addDoorInfo(
       update,
       PATH_TO_DOORS.newChild(info.getIdentifier()),
       info,
       TimeUnit.MILLISECONDS.toSeconds((long) (EXPIRATION_FACTOR * info.getUpdateTime())));
   _sum.enqueueUpdate(update);
 }
Example #6
0
 /**
  * Add a string metric at a specific point in the State tree if the value is not NULL.
  *
  * @param update the StateUpdate to append with the metric definition
  * @param parentPath the path to the parent branch for this metric
  * @param name the name of the metric
  * @param value the metric's value, or null if the metric should not be added.
  * @param storeTime how long, in seconds the metric should be preserved.
  */
 private void conditionalAddString(
     StateUpdate update, StatePath parentPath, String name, String value, long storeTime) {
   if (value != null) {
     update.appendUpdate(parentPath.newChild(name), new StringStateValue(value, storeTime));
   }
 }
 /**
  * Build a path to a description's summary information based on a voBasePath (something like
  * <code>summary.reservations.by-vo.atlas</code>. The returned path is something like: <code>
  * summary.reservations.by-vo.atlas.by-description.MCDISK</code>
  *
  * @param voBasePath
  * @param description
  * @return
  */
 private static StatePath buildDescriptionPath(StatePath voBasePath, String description) {
   return voBasePath.newChild(PATH_ELEMENT_BY_DESCRIPTION_BRANCH).newChild(description);
 }
/**
 * The ReservationByDescMaintainer class implements StateWatcher. It maintains an aggregation of SRM
 * reservations by (description, VO) ordered pairs: the space statics of SRM reservations that have
 * the same reservation description are aggregated.
 */
public class ReservationByDescMaintainer extends AbstractStateWatcher {

  private static Logger _log = LoggerFactory.getLogger(ReservationByDescMaintainer.class);

  public static final String PATH_ELEMENT_BY_DESCRIPTION_BRANCH = "by-description";

  public static final String PATH_ELEMENT_VO_NAME_METRIC = "vo";

  public static final String PATH_ELEMENT_SPACE_BRANCH = "space";

  public static final String PATH_ELEMENT_TOTAL_METRIC = "total";
  public static final String PATH_ELEMENT_ALLOCATED_METRIC = "allocated";
  public static final String PATH_ELEMENT_USED_METRIC = "used";
  public static final String PATH_ELEMENT_FREE_METRIC = "free";

  public static final String PATH_ELEMENT_RESERVATIONS_BRANCH = "reservations";

  public static final StatePath RESERVATIONS_BASE_PATH =
      StatePath.parsePath("summary.reservations.by-VO");

  private static final String PREDICATE_PATHS[] = {
    "reservations.*",
    "reservations.*.space.*",
    "reservations.*.description",
    "reservations.*.state",
    "reservations.*.authorisation.group"
  };

  /** Information aggregated over all reservations with the same description for the same VO. */
  private class ReservationSummaryInfo {
    private long _total;
    private long _free;
    private long _allocated;
    private long _used;
    private final Set<String> _ids = new HashSet<>();

    @Override
    public int hashCode() {
      return (int) _total ^ (int) _free ^ (int) _allocated ^ (int) _used ^ _ids.hashCode();
    }

    @Override
    public boolean equals(Object other) {
      if (this == other) {
        return true;
      }

      if (!(other instanceof ReservationSummaryInfo)) {
        return false;
      }

      ReservationSummaryInfo otherSummary = (ReservationSummaryInfo) other;

      if (otherSummary._total != _total
          || otherSummary._free != _free
          || otherSummary._allocated != _allocated
          || otherSummary._used != _used) {
        return false;
      }

      return otherSummary._ids.equals(_ids);
    }

    /**
     * Add a SRM reservation to this Reservation summary.
     *
     * @param reservationId the ID of this reservation.
     * @param info the information about this reservation.
     */
    public void addReservationInfo(String reservationId, ReservationInfo info) {
      if (info.hasTotal()) {
        _total += info.getTotal();
      }
      if (info.hasUsed()) {
        _used += info.getUsed();
      }
      if (info.hasFree()) {
        _free += info.getFree();
      }
      if (info.hasAllocated()) {
        _allocated += info.getAllocated();
      }
      _ids.add(reservationId);
    }

    public boolean hasId(String ID) {
      return _ids.contains(ID);
    }

    public long getTotal() {
      return _total;
    }

    public long getUsed() {
      return _used;
    }

    public long getFree() {
      return _free;
    }

    public long getAllocated() {
      return _allocated;
    }

    public boolean totalNeedsUpdating(ReservationSummaryInfo oldInfo) {
      return oldInfo == null || oldInfo.getTotal() != getTotal();
    }

    public boolean usedNeedsUpdating(ReservationSummaryInfo oldInfo) {
      return oldInfo == null || oldInfo.getUsed() != getUsed();
    }

    public boolean freeNeedsUpdating(ReservationSummaryInfo oldInfo) {
      return oldInfo == null || oldInfo.getFree() != getFree();
    }

    public boolean allocatedNeedsUpdating(ReservationSummaryInfo oldInfo) {
      return oldInfo == null || oldInfo.getAllocated() != getAllocated();
    }

    /**
     * Purge all IDs that are not present in this ReservationSummaryInfo but are missing from a new
     * version of ReservationSummaryInfo
     *
     * @param update the StateUpdate to add adjust.
     * @param basePath the base path of the IDs
     * @param newInfo the new version of this ReservationSummaryInfo
     */
    public void purgeMissingIds(
        StateUpdate update, StatePath basePath, ReservationSummaryInfo newInfo) {
      for (String id : _ids) {
        if (!newInfo.hasId(id)) {
          update.purgeUnder(basePath.newChild(id));
        }
      }
    }

    /**
     * Update the provided StateUpdate object so that later processing this StateUpdate will alter
     * dCache state such that it reflects the information held in this object.
     *
     * @param update the StateUpdate to use
     * @param voName the name of the VO
     * @param basePath the StatePath under which metrics will be added
     * @param oldInfo the previous ReservationSummaryInfo or null if this description is new.
     */
    public void updateMetrics(
        StateUpdate update, String voName, StatePath basePath, ReservationSummaryInfo oldInfo) {

      StatePath spacePath = basePath.newChild(PATH_ELEMENT_SPACE_BRANCH);

      if (totalNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_TOTAL_METRIC), new IntegerStateValue(getTotal(), true));
      }

      if (freeNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_FREE_METRIC), new IntegerStateValue(getFree(), true));
      }

      if (allocatedNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_ALLOCATED_METRIC),
            new IntegerStateValue(getAllocated(), true));
      }

      if (usedNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_USED_METRIC), new IntegerStateValue(getUsed(), true));
      }

      StatePath resvPath = basePath.newChild(PATH_ELEMENT_RESERVATIONS_BRANCH);

      /* Activity if there was an existing summary information */
      if (oldInfo != null) {
        oldInfo.purgeMissingIds(update, resvPath, this);

        /* Add those entries that are new */
        for (String newId : _ids) {
          if (!oldInfo.hasId(newId)) {
            update.appendUpdate(resvPath.newChild(newId), new StateComposite(true));
          }
        }

      } else {
        /* Add the VO name (we need to this only once) */
        update.appendUpdate(
            basePath.newChild(PATH_ELEMENT_VO_NAME_METRIC), new StringStateValue(voName, true));

        /* Add all IDs */
        for (String id : _ids) {
          update.appendUpdate(resvPath.newChild(id), new StateComposite(true));
        }
      }
    }
  }

  @Override
  protected String[] getPredicates() {
    return PREDICATE_PATHS;
  }

  @Override
  public void trigger(StateUpdate update, StateExhibitor currentState, StateExhibitor futureState) {
    Map<String, ReservationInfo> currentResv = ReservationInfoVisitor.getDetails(currentState);
    Map<String, ReservationInfo> futureResv = ReservationInfoVisitor.getDetails(futureState);

    // build mapping from description to summary data
    Map<String, Map<String, ReservationSummaryInfo>> currentSummary = buildSummaryInfo(currentResv);
    Map<String, Map<String, ReservationSummaryInfo>> futureSummary = buildSummaryInfo(futureResv);

    purgeMissingSummaries(update, currentSummary, futureSummary);
    addMetrics(update, currentSummary, futureSummary);
  }

  /**
   * Build a Map between VO name and a collection of reservation summary information. This
   * collection of reservation summary information is itself a Map between the reservation
   * description and a summary of all reservations with that same description. Those reservations
   * without a description are ignored.
   *
   * @param reservations a Map between reservation ID and a corresponding ReservationInfo object
   *     describing that reservation.
   * @return a Map of VO to reservation-description summaries.
   */
  private Map<String, Map<String, ReservationSummaryInfo>> buildSummaryInfo(
      Map<String, ReservationInfo> reservations) {
    Map<String, Map<String, ReservationSummaryInfo>> summary = new HashMap<>();

    for (Map.Entry<String, ReservationInfo> entry : reservations.entrySet()) {
      String reservationId = entry.getKey();
      ReservationInfo info = entry.getValue();

      /*
       * Ignore those reservations that don't have a state or that
       * state is a final one
       */
      if (!info.hasState() || info.getState().isFinalState()) {
        _log.debug("ignoring reservation " + reservationId + " as state is undefined or final");
        continue;
      }

      /* Skip those reservations that don't have a description */
      if (!info.hasDescription() || info.getDescription().isEmpty()) {
        _log.debug(
            "ignoring reservation " + reservationId + " as description is undefined or empty");
        continue;
      }

      /* Skip all those reservations that don't have a well-defined VO */
      if (!info.hasVo() || info.getVo().isEmpty()) {
        _log.debug("ignoring reservation " + reservationId + " as VO is undefined or empty");
        continue;
      }

      String voName = info.getVo();

      ReservationSummaryInfo thisSummary;

      Map<String, ReservationSummaryInfo> thisVoSummary;

      thisVoSummary = summary.get(voName);

      if (thisVoSummary == null) {
        thisVoSummary = new HashMap<>();
        summary.put(voName, thisVoSummary);
      }

      thisSummary = thisVoSummary.get(info.getDescription());

      if (thisSummary == null) {
        thisSummary = new ReservationSummaryInfo();
        thisVoSummary.put(info.getDescription(), thisSummary);
      }

      // update summary with this reservation.
      thisSummary.addReservationInfo(reservationId, info);
    }

    return summary;
  }

  /**
   * Adjust the StateUpdate object so that those descriptions that have disappeared are purged.
   *
   * @param update
   * @param currentDescriptions
   * @param futureDescriptions
   */
  private void purgeMissingSummaries(
      StateUpdate update,
      Map<String, Map<String, ReservationSummaryInfo>> currentVoInfo,
      Map<String, Map<String, ReservationSummaryInfo>> futureVoInfo) {

    for (Map.Entry<String, Map<String, ReservationSummaryInfo>> voEntry :
        currentVoInfo.entrySet()) {
      String voName = voEntry.getKey();
      Set<String> currentDescriptions = voEntry.getValue().keySet();

      StatePath voBasePath = buildVoPath(voName);

      Map<String, ReservationSummaryInfo> futureDescriptions = futureVoInfo.get(voName);

      // If this VO is gone completely, purge everything and move on.
      if (futureDescriptions == null) {
        update.purgeUnder(voBasePath);
        continue;
      }

      // Otherwise, purge those descriptions that have gone.
      for (String thisDescription : currentDescriptions) {
        if (!futureDescriptions.containsKey(thisDescription)) {
          update.purgeUnder(buildDescriptionPath(voBasePath, thisDescription));
        }
      }
    }
  }

  /**
   * Add metrics that update dCache state to reflect the changes. We assume those elements that
   * should be removed have been purged
   *
   * @param update
   * @param currentSummary
   * @param futureSummary
   */
  private void addMetrics(
      StateUpdate update,
      Map<String, Map<String, ReservationSummaryInfo>> currentSummary,
      Map<String, Map<String, ReservationSummaryInfo>> futureSummary) {

    for (Map.Entry<String, Map<String, ReservationSummaryInfo>> voEntry :
        futureSummary.entrySet()) {
      String voName = voEntry.getKey();

      if (_log.isDebugEnabled()) {
        _log.debug("Checking vo " + voName);
      }

      Map<String, ReservationSummaryInfo> futureDescriptions = voEntry.getValue();
      Map<String, ReservationSummaryInfo> currentDescriptions = currentSummary.get(voName);

      StatePath voPath = buildVoPath(voName);

      /* Scan through descriptions after transition is applied */
      for (Map.Entry<String, ReservationSummaryInfo> entry : futureDescriptions.entrySet()) {
        String description = entry.getKey();
        ReservationSummaryInfo futureInfo = entry.getValue();

        /*
         * Try to establish the corresponding current
         * ReservationSummaryInfo for this description
         */
        ReservationSummaryInfo currentInfo =
            currentDescriptions != null ? currentDescriptions.get(description) : null;

        if (!futureInfo.equals(currentInfo)) {
          futureInfo.updateMetrics(
              update, voName, buildDescriptionPath(voPath, description), currentInfo);
        }
      }
    }
  }

  /**
   * Build a StatePath for a given VO to the summary of that VO's SRM reservations; for example,
   * <code>summary.reservations.by-vo.atlas</code>
   *
   * @param voName The name of the VO
   * @return a StatePath pointing to the "by-description" part of this VO's reservation summary.
   */
  private static StatePath buildVoPath(String voName) {
    if (voName == null) {
      throw new IllegalArgumentException("voName is null");
    }

    return RESERVATIONS_BASE_PATH.newChild(voName);
  }

  /**
   * Build a path to a description's summary information based on a voBasePath (something like
   * <code>summary.reservations.by-vo.atlas</code>. The returned path is something like: <code>
   * summary.reservations.by-vo.atlas.by-description.MCDISK</code>
   *
   * @param voBasePath
   * @param description
   * @return
   */
  private static StatePath buildDescriptionPath(StatePath voBasePath, String description) {
    return voBasePath.newChild(PATH_ELEMENT_BY_DESCRIPTION_BRANCH).newChild(description);
  }
}
    /**
     * Update the provided StateUpdate object so that later processing this StateUpdate will alter
     * dCache state such that it reflects the information held in this object.
     *
     * @param update the StateUpdate to use
     * @param voName the name of the VO
     * @param basePath the StatePath under which metrics will be added
     * @param oldInfo the previous ReservationSummaryInfo or null if this description is new.
     */
    public void updateMetrics(
        StateUpdate update, String voName, StatePath basePath, ReservationSummaryInfo oldInfo) {

      StatePath spacePath = basePath.newChild(PATH_ELEMENT_SPACE_BRANCH);

      if (totalNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_TOTAL_METRIC), new IntegerStateValue(getTotal(), true));
      }

      if (freeNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_FREE_METRIC), new IntegerStateValue(getFree(), true));
      }

      if (allocatedNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_ALLOCATED_METRIC),
            new IntegerStateValue(getAllocated(), true));
      }

      if (usedNeedsUpdating(oldInfo)) {
        update.appendUpdate(
            spacePath.newChild(PATH_ELEMENT_USED_METRIC), new IntegerStateValue(getUsed(), true));
      }

      StatePath resvPath = basePath.newChild(PATH_ELEMENT_RESERVATIONS_BRANCH);

      /* Activity if there was an existing summary information */
      if (oldInfo != null) {
        oldInfo.purgeMissingIds(update, resvPath, this);

        /* Add those entries that are new */
        for (String newId : _ids) {
          if (!oldInfo.hasId(newId)) {
            update.appendUpdate(resvPath.newChild(newId), new StateComposite(true));
          }
        }

      } else {
        /* Add the VO name (we need to this only once) */
        update.appendUpdate(
            basePath.newChild(PATH_ELEMENT_VO_NAME_METRIC), new StringStateValue(voName, true));

        /* Add all IDs */
        for (String id : _ids) {
          update.appendUpdate(resvPath.newChild(id), new StateComposite(true));
        }
      }
    }