
com.hazelcast.jclouds.ComputeServiceBuilder Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.jclouds;
import com.google.common.base.Charsets;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.io.Files;
import com.hazelcast.config.InvalidConfigurationException;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.config.properties.PropertyDefinition;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import org.jclouds.Constants;
import org.jclouds.ContextBuilder;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.googlecloud.GoogleCredentialsFromJson;
import org.jclouds.location.reference.LocationConstants;
import java.io.File;
import java.io.IOException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import static com.hazelcast.util.Preconditions.checkNotNull;
import static com.hazelcast.util.Preconditions.isNotNull;
/**
* ComputeServiceBuilder is the responsible class for building jclouds compute service provider.
* Also parses config and applies necessary filters on cluster nodes.
*/
public class ComputeServiceBuilder {
private static final String GOOGLE_COMPUTE_ENGINE = "google-compute-engine";
private static final String AWS_EC2 = "aws-ec2";
private static final String JCLOUD_CONNECTION_TIMEOUT = "10000";
private static final ILogger LOGGER = Logger.getLogger(ComputeServiceBuilder.class);
private final Map properties;
private Set regionsSet = new LinkedHashSet();
private Set zonesSet = new LinkedHashSet();
private List tagPairs = new ArrayList();
private Predicate nodesFilter;
private ComputeService computeService;
/**
* Instantiates a new Compute service builder.
*
* @param properties the properties
*/
ComputeServiceBuilder(Map properties) {
checkNotNull(properties, "Props cannot be null");
this.properties = properties;
}
public Map getProperties() {
return properties;
}
public Set getRegionsSet() {
return regionsSet;
}
public Set getZonesSet() {
return zonesSet;
}
public List getTagPairs() {
return tagPairs;
}
/**
* Injects already built ComputeService
* @param computeService
*/
public void setComputeService(ComputeService computeService) {
this.computeService = computeService;
}
/**
* Gets filtered nodes.
*
* @return the filtered nodes
*/
public Iterable extends NodeMetadata> getFilteredNodes() {
final String group = getOrNull(JCloudsProperties.GROUP);
Set extends NodeMetadata> result = computeService.listNodesDetailsMatching(nodesFilter);
Iterable extends NodeMetadata> filteredResult = new HashSet();
for (NodeMetadata metadata : result) {
if (group != null && !group.equals(metadata.getGroup())) {
continue;
}
if (!isNodeInsideZones(metadata) || !isNodeInsideRegions(metadata)) {
continue;
}
((HashSet) filteredResult).add(metadata);
}
return filteredResult;
}
public int getServicePort() {
return getOrDefault(JCloudsProperties.HZ_PORT, NetworkConfig.DEFAULT_PORT);
}
public boolean isNodeInsideZones(NodeMetadata metadata) {
Location location = metadata.getLocation();
while (location != null) {
String id = location.getId();
if (location.getScope().equals(LocationScope.ZONE)) {
if (id != null && !zonesSet.isEmpty() && !zonesSet.contains(id)) {
return false;
}
}
location = location.getParent();
}
return true;
}
public boolean isNodeInsideRegions(NodeMetadata metadata) {
Location location = metadata.getLocation();
while (location != null) {
String id = location.getId();
if (location.getScope().equals(LocationScope.REGION)) {
if (id != null && !regionsSet.isEmpty() && !regionsSet.contains(id)) {
return false;
}
}
location = location.getParent();
}
return true;
}
/**
*/
public void destroy() {
if (computeService != null) {
this.computeService.getContext().close();
}
}
/**
* Build compute service.
*
* @return the compute service
*/
ComputeService build() {
final String cloudProvider = getOrNull(JCloudsProperties.PROVIDER);
final String identity = getOrNull(JCloudsProperties.IDENTITY);
String credential = getOrNull(JCloudsProperties.CREDENTIAL);
final String credentialPath = getOrNull(JCloudsProperties.CREDENTIAL_PATH);
isNotNull(cloudProvider, "Cloud Provider");
if (credential != null && credentialPath != null) {
throw new UnsupportedOperationException("Both credential and credentialPath are set. Use only one method.");
}
if (credentialPath != null) {
credential = getCredentialFromFile(credential, credentialPath);
}
if (LOGGER.isFinestEnabled()) {
LOGGER.finest("Using CLOUD_PROVIDER: " + cloudProvider);
}
final String roleName = getOrNull(JCloudsProperties.ROLE_NAME);
ContextBuilder contextBuilder = newContextBuilder(cloudProvider, identity, credential, roleName);
Properties jcloudsProperties = buildRegionZonesConfig();
buildTagConfig();
buildNodeFilter();
computeService = contextBuilder.overrides(jcloudsProperties)
.buildView(ComputeServiceContext.class)
.getComputeService();
return computeService;
}
public Properties buildRegionZonesConfig() {
final String regions = getOrNull(JCloudsProperties.REGIONS);
final String zones = getOrNull(JCloudsProperties.ZONES);
Properties jcloudsProperties = newOverrideProperties();
if (regions != null) {
List regionList = Arrays.asList(regions.split(","));
for (String region : regionList) {
regionsSet.add(region);
}
jcloudsProperties.setProperty(LocationConstants.PROPERTY_REGIONS, regions);
}
if (zones != null) {
List zoneList = Arrays.asList(zones.split(","));
for (String zone : zoneList) {
zonesSet.add(zone);
}
jcloudsProperties.setProperty(LocationConstants.PROPERTY_ZONES, zones);
}
return jcloudsProperties;
}
public void buildTagConfig() {
final String tagKeys = getOrNull(JCloudsProperties.TAG_KEYS);
final String tagValues = getOrNull(JCloudsProperties.TAG_VALUES);
if (tagKeys != null && tagValues != null) {
List keysList = Arrays.asList(tagKeys.split(","));
List valueList = Arrays.asList(tagValues.split(","));
if (keysList.size() != valueList.size()) {
throw new InvalidConfigurationException("Tags keys and value count does not match.");
}
for (int i = 0; i < keysList.size(); i++) {
tagPairs.add(new AbstractMap.SimpleImmutableEntry(keysList.get(i), valueList.get(i)));
}
}
}
public Predicate buildNodeFilter() {
nodesFilter = new Predicate() {
@Override
public boolean apply(ComputeMetadata nodeMetadata) {
if (nodeMetadata == null) {
return false;
}
if (tagPairs.size() > nodeMetadata.getUserMetadata().size()) {
return false;
}
for (AbstractMap.SimpleImmutableEntry entry: tagPairs) {
String value = nodeMetadata.getUserMetadata().get(entry.getKey());
if (value == null || !value.equals(entry.getValue())) {
return false;
}
}
return true;
}
};
return nodesFilter;
}
public String getCredentialFromFile(String provider, String credentialPath) throws IllegalArgumentException {
try {
String fileContents = Files.toString(new File(credentialPath), Charsets.UTF_8);
if (provider.equals(GOOGLE_COMPUTE_ENGINE)) {
Supplier credentialSupplier = new GoogleCredentialsFromJson(fileContents);
return credentialSupplier.get().credential;
}
return fileContents;
} catch (IOException e) {
throw new InvalidConfigurationException("Failed to retrieve the private key from the file: " + credentialPath, e);
}
}
public ContextBuilder newContextBuilder(final String cloudProvider, final String identity,
final String credential, final String roleName) {
try {
if (roleName != null && (identity != null || credential != null)) {
throw new InvalidConfigurationException("IAM role is configured, identity "
+ "or credential propery is not allowed.");
}
if (roleName != null && !cloudProvider.equals(AWS_EC2)) {
throw new InvalidConfigurationException("IAM role is only supported with aws-ec2, your cloud "
+ "provider is " + cloudProvider);
}
if (cloudProvider.equals(AWS_EC2) && roleName != null) {
Supplier credentialsSupplier = new Supplier() {
@Override
public Credentials get() {
return new IAMRoleCredentialSupplierBuilder().
withRoleName(roleName).build();
}
};
return ContextBuilder.newBuilder(cloudProvider).credentialsSupplier(credentialsSupplier);
} else {
checkNotNull(identity, "Cloud provider identity is not set");
checkNotNull(credential, "Cloud provider credential is not set");
return ContextBuilder.newBuilder(cloudProvider).credentials(identity, credential);
}
} catch (NoSuchElementException e) {
throw new InvalidConfigurationException("Unrecognized cloud-provider [" + cloudProvider + "]");
}
}
private Properties newOverrideProperties() {
Properties properties = new Properties();
properties.setProperty(Constants.PROPERTY_SO_TIMEOUT, JCLOUD_CONNECTION_TIMEOUT);
properties.setProperty(Constants.PROPERTY_CONNECTION_TIMEOUT, JCLOUD_CONNECTION_TIMEOUT);
return properties;
}
private T getOrNull(PropertyDefinition property) {
return getOrDefault(property, null);
}
private T getOrDefault(PropertyDefinition property, T defaultValue) {
if (properties == null || property == null) {
return defaultValue;
}
Comparable value = properties.get(property.key());
if (value == null) {
return defaultValue;
}
return (T) value;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy