/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.worker; import alluxio.Configuration; import alluxio.PropertyKey; import alluxio.RestUtils; import alluxio.RuntimeConstants; import alluxio.WorkerStorageTierAssoc; import alluxio.metrics.MetricsSystem; import alluxio.web.WorkerWebServer; import alluxio.wire.AlluxioWorkerInfo; import alluxio.wire.Capacity; import alluxio.worker.block.BlockStoreMeta; import alluxio.worker.block.BlockWorker; import alluxio.worker.block.DefaultBlockWorker; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; import com.codahale.metrics.MetricRegistry; import com.qmino.miredot.annotations.ReturnType; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import javax.annotation.concurrent.NotThreadSafe; import javax.servlet.ServletContext; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; /** * This class is a REST handler for requesting general worker information. */ @NotThreadSafe @Path(AlluxioWorkerRestServiceHandler.SERVICE_PREFIX) @Produces(MediaType.APPLICATION_JSON) public final class AlluxioWorkerRestServiceHandler { public static final String SERVICE_PREFIX = "worker"; // endpoints public static final String GET_INFO = "info"; // queries public static final String QUERY_RAW_CONFIGURATION = "raw_configuration"; // the following endpoints are deprecated public static final String GET_RPC_ADDRESS = "rpc_address"; public static final String GET_CAPACITY_BYTES = "capacity_bytes"; public static final String GET_CONFIGURATION = "configuration"; public static final String GET_USED_BYTES = "used_bytes"; public static final String GET_CAPACITY_BYTES_ON_TIERS = "capacity_bytes_on_tiers"; public static final String GET_USED_BYTES_ON_TIERS = "used_bytes_on_tiers"; public static final String GET_DIRECTORY_PATHS_ON_TIERS = "directory_paths_on_tiers"; public static final String GET_START_TIME_MS = "start_time_ms"; public static final String GET_UPTIME_MS = "uptime_ms"; public static final String GET_VERSION = "version"; public static final String GET_METRICS = "metrics"; private final WorkerProcess mWorkerProcess; private final BlockStoreMeta mStoreMeta; /** * @param context context for the servlet */ public AlluxioWorkerRestServiceHandler(@Context ServletContext context) { mWorkerProcess = (WorkerProcess) context .getAttribute(WorkerWebServer.ALLUXIO_WORKER_SERVLET_RESOURCE_KEY); mStoreMeta = mWorkerProcess.getWorker(BlockWorker.class).getStoreMeta(); } /** * @summary get the Alluxio master information * @param rawConfiguration if it's true, raw configuration values are returned, * otherwise, they are looked up; if it's not provided in URL queries, then * it is null, which means false. * @return the response object */ @GET @Path(GET_INFO) @ReturnType("alluxio.wire.AlluxioWorkerInfo") public Response getInfo(@QueryParam(QUERY_RAW_CONFIGURATION) final Boolean rawConfiguration) { // TODO(jiri): Add a mechanism for retrieving only a subset of the fields. return RestUtils.call(new RestUtils.RestCallable<AlluxioWorkerInfo>() { @Override public AlluxioWorkerInfo call() throws Exception { boolean rawConfig = false; if (rawConfiguration != null) { rawConfig = rawConfiguration; } AlluxioWorkerInfo result = new AlluxioWorkerInfo() .setCapacity(getCapacityInternal()) .setConfiguration(getConfigurationInternal(rawConfig)) .setMetrics(getMetricsInternal()) .setRpcAddress(mWorkerProcess.getRpcAddress().toString()) .setStartTimeMs(mWorkerProcess.getStartTimeMs()) .setTierCapacity(getTierCapacityInternal()) .setTierPaths(getTierPathsInternal()) .setUptimeMs(mWorkerProcess.getUptimeMs()) .setVersion(RuntimeConstants.VERSION); return result; } }); } /** * @summary get the configuration map, the keys are ordered alphabetically. * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_CONFIGURATION) @ReturnType("java.util.SortedMap<java.lang.String, java.lang.String>") @Deprecated public Response getConfiguration() { return RestUtils.call(new RestUtils.RestCallable<Map<String, String>>() { @Override public Map<String, String> call() throws Exception { return getConfigurationInternal(true); } }); } /** * @summary get the address of the worker * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_RPC_ADDRESS) @ReturnType("java.lang.String") @Deprecated public Response getRpcAddress() { return RestUtils.call(new RestUtils.RestCallable<String>() { @Override public String call() throws Exception { return mWorkerProcess.getRpcAddress().toString(); } }); } /** * @summary get the total capacity of the worker in bytes * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_CAPACITY_BYTES) @ReturnType("java.lang.Long") @Deprecated public Response getCapacityBytes() { return RestUtils.call(new RestUtils.RestCallable<Long>() { @Override public Long call() throws Exception { return mStoreMeta.getCapacityBytes(); } }); } /** * @summary get the used bytes of the worker * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_USED_BYTES) @ReturnType("java.lang.Long") @Deprecated public Response getUsedBytes() { return RestUtils.call(new RestUtils.RestCallable<Long>() { @Override public Long call() throws Exception { return mStoreMeta.getUsedBytes(); } }); } /** * @summary get the mapping from tier alias to the total capacity of the tier in bytes, the keys * are in the order from tier aliases with smaller ordinals to those with larger ones. * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_CAPACITY_BYTES_ON_TIERS) @ReturnType("java.util.SortedMap<java.lang.String, java.lang.Long>") @Deprecated public Response getCapacityBytesOnTiers() { return RestUtils.call(new RestUtils.RestCallable<Map<String, Long>>() { @Override public Map<String, Long> call() throws Exception { SortedMap<String, Long> capacityBytesOnTiers = new TreeMap<>(getTierAliasComparator()); for (Map.Entry<String, Long> tierBytes : mStoreMeta.getCapacityBytesOnTiers().entrySet()) { capacityBytesOnTiers.put(tierBytes.getKey(), tierBytes.getValue()); } return capacityBytesOnTiers; } }); } /** * @summary get the mapping from tier alias to the used bytes of the tier, the keys are in the * order from tier aliases with smaller ordinals to those with larger ones. * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_USED_BYTES_ON_TIERS) @ReturnType("java.util.SortedMap<java.lang.String, java.lang.Long>") @Deprecated public Response getUsedBytesOnTiers() { return RestUtils.call(new RestUtils.RestCallable<Map<String, Long>>() { @Override public Map<String, Long> call() throws Exception { SortedMap<String, Long> usedBytesOnTiers = new TreeMap<>(getTierAliasComparator()); for (Map.Entry<String, Long> tierBytes : mStoreMeta.getUsedBytesOnTiers().entrySet()) { usedBytesOnTiers.put(tierBytes.getKey(), tierBytes.getValue()); } return usedBytesOnTiers; } }); } /** * @summary get the mapping from tier alias to the paths of the directories in the tier * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_DIRECTORY_PATHS_ON_TIERS) @ReturnType("java.util.SortedMap<java.lang.String, java.util.List<java.lang.String>>") @Deprecated public Response getDirectoryPathsOnTiers() { return RestUtils.call(new RestUtils.RestCallable<Map<String, List<String>>>() { @Override public Map<String, List<String>> call() throws Exception { return getTierPathsInternal(); } }); } /** * @summary get the version of the worker * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_VERSION) @ReturnType("java.lang.String") @Deprecated public Response getVersion() { return RestUtils.call(new RestUtils.RestCallable<String>() { @Override public String call() throws Exception { return RuntimeConstants.VERSION; } }); } /** * @summary get the start time of the worker in milliseconds * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_START_TIME_MS) @ReturnType("java.lang.Long") @Deprecated public Response getStartTimeMs() { return RestUtils.call(new RestUtils.RestCallable<Long>() { @Override public Long call() throws Exception { return mWorkerProcess.getStartTimeMs(); } }); } /** * @summary get the uptime of the worker in milliseconds * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_UPTIME_MS) @ReturnType("java.lang.Long") @Deprecated public Response getUptimeMs() { return RestUtils.call(new RestUtils.RestCallable<Long>() { @Override public Long call() throws Exception { return mWorkerProcess.getUptimeMs(); } }); } /** * @summary get the worker metrics * @return the response object * @deprecated since version 1.4 and will be removed in version 2.0 * @see #getInfo(Boolean) */ @GET @Path(GET_METRICS) @ReturnType("java.util.SortedMap<java.lang.String, java.lang.Long>") @Deprecated public Response getMetrics() { return RestUtils.call(new RestUtils.RestCallable<Map<String, Long>>() { @Override public Map<String, Long> call() throws Exception { return getMetricsInternal(); } }); } private Capacity getCapacityInternal() { return new Capacity().setTotal(mStoreMeta.getCapacityBytes()) .setUsed(mStoreMeta.getUsedBytes()); } private Map<String, String> getConfigurationInternal(boolean raw) { Set<Map.Entry<String, String>> properties = Configuration.toMap().entrySet(); SortedMap<String, String> configuration = new TreeMap<>(); for (Map.Entry<String, String> entry : properties) { String key = entry.getKey(); if (PropertyKey.isValid(key)) { if (raw) { configuration.put(key, entry.getValue()); } else { configuration.put(key, Configuration.get(PropertyKey.fromString(key))); } } } return configuration; } private Map<String, Long> getMetricsInternal() { MetricRegistry metricRegistry = MetricsSystem.METRIC_REGISTRY; // Get all counters. Map<String, Counter> counters = metricRegistry.getCounters(); // Only the gauge for cached blocks is retrieved here, other gauges are statistics of // free/used spaces, those statistics can be gotten via other REST apis. String blocksCachedProperty = MetricsSystem.getWorkerMetricName(DefaultBlockWorker.Metrics.BLOCKS_CACHED); @SuppressWarnings("unchecked") Gauge<Integer> blocksCached = (Gauge<Integer>) metricRegistry.getGauges().get(blocksCachedProperty); // Get values of the counters and gauges and put them into a metrics map. SortedMap<String, Long> metrics = new TreeMap<>(); for (Map.Entry<String, Counter> counter : counters.entrySet()) { metrics.put(counter.getKey(), counter.getValue().getCount()); } metrics.put(blocksCachedProperty, blocksCached.getValue().longValue()); return metrics; } private Comparator<String> getTierAliasComparator() { return new Comparator<String>() { private WorkerStorageTierAssoc mTierAssoc = new WorkerStorageTierAssoc(); @Override public int compare(String tier1, String tier2) { int ordinal1 = mTierAssoc.getOrdinal(tier1); int ordinal2 = mTierAssoc.getOrdinal(tier2); if (ordinal1 < ordinal2) { return -1; } if (ordinal1 == ordinal2) { return 0; } return 1; } }; } private Map<String, Capacity> getTierCapacityInternal() { SortedMap<String, Capacity> tierCapacity = new TreeMap<>(getTierAliasComparator()); Map<String, Long> capacityBytesOnTiers = mStoreMeta.getCapacityBytesOnTiers(); Map<String, Long> usedBytesOnTiers = mStoreMeta.getUsedBytesOnTiers(); for (Map.Entry<String, Long> entry : capacityBytesOnTiers.entrySet()) { tierCapacity.put(entry.getKey(), new Capacity().setTotal(entry.getValue()).setUsed(usedBytesOnTiers.get(entry.getKey()))); } return tierCapacity; } private Map<String, List<String>> getTierPathsInternal() { SortedMap<String, List<String>> tierToDirPaths = new TreeMap<>(getTierAliasComparator()); tierToDirPaths.putAll(mStoreMeta.getDirectoryPathsOnTiers()); return tierToDirPaths; } }