/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.drill.exec.server.rest; import java.util.Collection; import javax.annotation.security.PermitAll; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.SecurityContext; import javax.xml.bind.annotation.XmlRootElement; import com.google.common.base.Strings; import com.google.common.collect.Sets; import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint; import org.apache.drill.exec.server.rest.DrillRestServer.UserAuthEnabled; import org.apache.drill.exec.work.WorkManager; import org.glassfish.jersey.server.mvc.Viewable; import com.fasterxml.jackson.annotation.JsonCreator; @Path("/") @PermitAll public class DrillRoot { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillRoot.class); @Inject UserAuthEnabled authEnabled; @Inject WorkManager work; @Inject SecurityContext sc; @GET @Produces(MediaType.TEXT_HTML) public Viewable getClusterInfo() { return ViewableWithPermissions.create(authEnabled.get(), "/rest/index.ftl", sc, getClusterInfoJSON()); } @GET @Path("/cluster.json") @Produces(MediaType.APPLICATION_JSON) public ClusterInfo getClusterInfoJSON() { final Collection<DrillbitInfo> drillbits = Sets.newTreeSet(); final Collection<String> mismatchedVersions = Sets.newTreeSet(); final DrillbitEndpoint currentDrillbit = work.getContext().getEndpoint(); final String currentVersion = currentDrillbit.getVersion(); for (DrillbitEndpoint endpoint : work.getContext().getBits()) { final DrillbitInfo drillbit = new DrillbitInfo(endpoint, currentDrillbit.equals(endpoint), currentVersion.equals(endpoint.getVersion())); if (!drillbit.isVersionMatch()) { mismatchedVersions.add(drillbit.getVersion()); } drillbits.add(drillbit); } return new ClusterInfo(drillbits, currentVersion, mismatchedVersions); } @XmlRootElement public static class ClusterInfo { private final Collection<DrillbitInfo> drillbits; private final String currentVersion; private final Collection<String> mismatchedVersions; @JsonCreator public ClusterInfo(Collection<DrillbitInfo> drillbits, String currentVersion, Collection<String> mismatchedVersions) { this.drillbits = Sets.newTreeSet(drillbits); this.currentVersion = currentVersion; this.mismatchedVersions = Sets.newTreeSet(mismatchedVersions); } public Collection<DrillbitInfo> getDrillbits() { return Sets.newTreeSet(drillbits); } public String getCurrentVersion() { return currentVersion; } public Collection<String> getMismatchedVersions() { return Sets.newTreeSet(mismatchedVersions); } } public static class DrillbitInfo implements Comparable<DrillbitInfo> { private final String address; private final String userPort; private final String controlPort; private final String dataPort; private final String version; private final boolean current; private final boolean versionMatch; @JsonCreator public DrillbitInfo(DrillbitEndpoint drillbit, boolean current, boolean versionMatch) { this.address = drillbit.getAddress(); this.userPort = String.valueOf(drillbit.getUserPort()); this.controlPort = String.valueOf(drillbit.getControlPort()); this.dataPort = String.valueOf(drillbit.getDataPort()); this.version = Strings.isNullOrEmpty(drillbit.getVersion()) ? "Undefined" : drillbit.getVersion(); this.current = current; this.versionMatch = versionMatch; } public String getAddress() { return address; } public String getUserPort() { return userPort; } public String getControlPort() { return controlPort; } public String getDataPort() { return dataPort; } public String getVersion() { return version; } public boolean isCurrent() { return current; } public boolean isVersionMatch() { return versionMatch; } /** * Method used to sort drillbits. Current drillbit goes first. * Then drillbits with matching versions, after them drillbits with mismatching versions. * Matching drillbits are sorted according address natural order, * mismatching drillbits are sorted according version, address natural order. * * @param drillbitToCompare drillbit to compare against * @return -1 if drillbit should be before, 1 if after in list */ @Override public int compareTo(DrillbitInfo drillbitToCompare) { if (this.isCurrent()) { return -1; } if (drillbitToCompare.isCurrent()) { return 1; } if (this.isVersionMatch() == drillbitToCompare.isVersionMatch()) { if (this.version.equals(drillbitToCompare.getVersion())) { return this.address.compareTo(drillbitToCompare.getAddress()); } return this.version.compareTo(drillbitToCompare.getVersion()); } return this.versionMatch ? -1 : 1; } } }