All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 getFilteredNodes() {
        final String group = getOrNull(JCloudsProperties.GROUP);
        Set result = computeService.listNodesDetailsMatching(nodesFilter);
        Iterable 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