blob: b6dfa30e1b11d27d53aed363b0ee2e673988b470 [file] [log] [blame]
/**
* 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.ambari.server.controller.gsinstaller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Defines the cluster created by gsInstaller.
*/
public class ClusterDefinition {
private static final String CLUSTER_DEFINITION_FILE = "gsInstaller-hosts.txt";
private static final String DEFAULT_CLUSTER_NAME = "ambari";
private static final String CLUSTER_NAME_TAG = "CLUSTER=";
private static final String DEFAULT_VERSION_ID = "HDP-1.2.0";
private static final String VERSION_ID_TAG = "VERSION=";
private final Set<String> services = new HashSet<String>();
private final Set<String> hosts = new HashSet<String>();
private final Map<String, Set<String>> components = new HashMap<String, Set<String>>();
private final Map<String, Map<String, Set<String>>> hostComponents = new HashMap<String, Map<String, Set<String>>>();
private final GSInstallerStateProvider stateProvider;
private String clusterName;
private String versionId;
/**
* Index of host names to host component state.
*/
private final Map<String, Set<HostComponentState>> hostStateMap = new HashMap<String, Set<HostComponentState>>();
/**
* Index of service names to host component state.
*/
private final Map<String, Set<HostComponentState>> serviceStateMap = new HashMap<String, Set<HostComponentState>>();
/**
* Index of component names to host component state.
*/
private final Map<String, Set<HostComponentState>> componentStateMap = new HashMap<String, Set<HostComponentState>>();
/**
* Index of host component names to host component state.
*/
private final Map<String, HostComponentState> hostComponentStateMap = new HashMap<String, HostComponentState>();
/**
* Expiry for the health value.
*/
private static final int DEFAULT_STATE_EXPIRY = 15000;
/**
* Component name mapping to account for differences in what is provided by the gsInstaller
* and what is expected by the Ambari providers.
*/
private static final Map<String, String> componentNameMap = new HashMap<String, String>();
static {
componentNameMap.put("GANGLIA", "GANGLIA_SERVER");
}
// ----- Constructors ------------------------------------------------------
/**
* Create a cluster definition.
*
* @param stateProvider the state provider
*/
public ClusterDefinition(GSInstallerStateProvider stateProvider) {
this(stateProvider, DEFAULT_STATE_EXPIRY);
}
/**
* Create a cluster definition.
*
* @param stateProvider the state provider
* @param stateExpiry the state expiry
*/
public ClusterDefinition(GSInstallerStateProvider stateProvider, int stateExpiry) {
this.stateProvider = stateProvider;
this.clusterName = DEFAULT_CLUSTER_NAME;
this.versionId = DEFAULT_VERSION_ID;
readClusterDefinition();
setHostComponentState(stateExpiry);
}
// ----- ClusterDefinition -------------------------------------------------
/**
* Get the name of the cluster.
*
* @return the cluster name
*/
public String getClusterName() {
return clusterName;
}
/**
* Get the name of the cluster.
*
* @return the cluster name
*/
public String getVersionId() {
return versionId;
}
/**
* Get the services for the cluster.
*
* @return the set of service names
*/
public Set<String> getServices() {
return services;
}
/**
* Get the hosts for the cluster.
*
* @return the set of hosts names
*/
public Set<String> getHosts() {
return hosts;
}
/**
* Get the components for the given service.
*
* @param service the service name
*
* @return the set of component names for the given service name
*/
public Set<String> getComponents(String service) {
return components.get(service);
}
/**
* Get the host components for the given service and host.
*
* @param service the service name
* @param host the host name
*
* @return the set of host component names for the given service and host names
*/
public Set<String> getHostComponents(String service, String host) {
Set<String> resultSet = null;
Map<String, Set<String>> serviceHostComponents = hostComponents.get(service);
if (serviceHostComponents != null) {
resultSet = serviceHostComponents.get(host);
}
return resultSet == null ? Collections.<String>emptySet() : resultSet;
}
/**
* Get the host state from the given host name.
*
* @param hostName the host name
*
* @return the host state
*/
public String getHostState(String hostName) {
return isHealthy(hostStateMap.get(hostName)) ? "HEALTHY" : "INIT";
}
/**
* Get the service state from the given service name.
*
* @param serviceName the service name
*
* @return the service state
*/
public String getServiceState(String serviceName) {
return isHealthy(serviceStateMap.get(serviceName)) ? "STARTED" : "INIT";
}
/**
* Get the component state from the give service name and component name.
*
* @param serviceName the service name
* @param componentName the component name
*
* @return the component state
*/
public String getComponentState(String serviceName, String componentName) {
return isHealthy(componentStateMap.get(getComponentKey(serviceName, componentName))) ? "STARTED" : "INIT";
}
/**
* Get the host component name from the given host name, service name and component name.
*
* @param hostName the host name
* @param serviceName the service name
* @param componentName the component name
*
* @return the host component state
*/
public String getHostComponentState(String hostName, String serviceName, String componentName) {
return isHealthy(hostComponentStateMap.get(getHostComponentKey(hostName, serviceName, componentName))) ? "STARTED" : "INIT";
}
// ----- helper methods ----------------------------------------------------
/**
* Read the gsInstaller cluster definition file.
*/
private void readClusterDefinition() {
try {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(CLUSTER_DEFINITION_FILE);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.startsWith(CLUSTER_NAME_TAG)) {
clusterName = line.substring(CLUSTER_NAME_TAG.length());
}
else if (line.startsWith(VERSION_ID_TAG)) {
versionId = line.substring(VERSION_ID_TAG.length());
}
else {
String[] parts = line.split("\\s+");
assert(parts.length == 3);
String serviceName = parts[0];
String componentName = parts[1];
String hostName = parts[2];
// translate the component name if required
if (componentNameMap.containsKey(componentName)) {
componentName = componentNameMap.get(componentName);
}
services.add(serviceName);
Set<String> serviceComponents = components.get(serviceName);
if (serviceComponents == null) {
serviceComponents = new HashSet<String>();
components.put(serviceName, serviceComponents);
}
serviceComponents.add(componentName);
Map<String, Set<String>> serviceHostComponents = hostComponents.get(serviceName);
if (serviceHostComponents == null) {
serviceHostComponents = new HashMap<String, Set<String>>();
hostComponents.put(serviceName, serviceHostComponents);
}
Set<String> hostHostComponents = serviceHostComponents.get(hostName);
if (hostHostComponents == null) {
hostHostComponents = new HashSet<String>();
serviceHostComponents.put(hostName, hostHostComponents);
}
hostHostComponents.add(componentName);
hosts.add(hostName);
}
}
} catch (IOException e) {
String msg = "Caught exception reading " + CLUSTER_DEFINITION_FILE + ".";
throw new IllegalStateException(msg, e);
}
}
/**
* Set the host component state maps.
*/
private void setHostComponentState(int stateExpiry) {
for (Map.Entry<String, Map<String, Set<String>>> serviceEntry : hostComponents.entrySet()) {
String serviceName = serviceEntry.getKey();
for (Map.Entry<String, Set<String>> hostEntry : serviceEntry.getValue().entrySet()) {
String hostName = hostEntry.getKey();
for (String componentName : hostEntry.getValue()) {
HostComponentState state = new HostComponentState(hostName, componentName, stateExpiry);
// add state to hosts
addState(hostName, hostStateMap, state);
// add state to services
addState(serviceName, serviceStateMap, state);
// add state to components
addState(getComponentKey(serviceName, componentName), componentStateMap, state);
// add state to host components
hostComponentStateMap.put(getHostComponentKey(hostName, serviceName, componentName), state);
}
}
}
}
/**
* Add the given host component state object to the given map of state objects.
*
* @param hostName the host name
* @param stateMap the map of state objects
* @param state the state
*/
private static void addState(String hostName, Map<String, Set<HostComponentState>> stateMap, HostComponentState state) {
Set<HostComponentState> states = stateMap.get(hostName);
if (states == null) {
states = new HashSet<HostComponentState>();
stateMap.put(hostName, states);
}
states.add(state);
}
/**
* Get a key from the given service name and component name.
*
* @param serviceName the service name
* @param componentName the component name
*
* @return the key
*/
private String getComponentKey(String serviceName, String componentName) {
return serviceName + "." + componentName;
}
/**
* Get a key from the given host name, service name and component name.
*
* @param hostName the host name
* @param serviceName the service name
* @param componentName the component name
*
* @return the key
*/
private String getHostComponentKey(String hostName, String serviceName, String componentName) {
return hostName + "." + serviceName + "." + componentName;
}
/**
* Determine whether or not the host components associated
* with the given states are healthy.
*
* @param states the states
*
* @return true if the associated host components are healthy
*/
private boolean isHealthy(Set<HostComponentState> states) {
if (states != null) {
for (HostComponentState state : states) {
if (!state.isHealthy()) {
return false;
}
}
}
return true;
}
/**
* Determine whether or not the host component associated
* with the given state is healthy.
*
* @param state the state
*
* @return true if the associated host component is healthy
*/
private boolean isHealthy(HostComponentState state) {
return state == null || state.isHealthy();
}
// ----- inner classes -----------------------------------------------------
/**
* A state object used to check the health of a host component.
*/
private class HostComponentState {
private final String hostName;
private final String componentName;
private final int expiry;
private boolean healthy = true;
private long lastAccess;
// ----- Constructor -----------------------------------------------------
/**
* Constructor.
*
* @param hostName the host name
* @param componentName the component name
*/
HostComponentState(String hostName, String componentName, int expiry) {
this.hostName = hostName;
this.componentName = componentName;
this.expiry = expiry;
}
/**
* Determine whether or not the associated host component is healthy.
*
* @return true if the associated host component is healthy
*/
public boolean isHealthy() {
if (System.currentTimeMillis() - lastAccess > expiry) {
// health value has expired... get it again
healthy = stateProvider.isHealthy(hostName, componentName);
this.lastAccess = System.currentTimeMillis();
}
return healthy;
}
}
}