/* * 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.hive.ptest.execution.context; import java.io.File; import java.io.IOException; import java.util.*; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.io.Files; import org.jclouds.Constants; import org.jclouds.ContextBuilder; import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.config.ComputeServiceProperties; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata.Status; import org.jclouds.compute.domain.Template; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.domain.Credentials; import org.jclouds.googlecloud.GoogleCredentialsFromJson; import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.sshj.config.SshjSshClientModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import static com.google.common.base.Charsets.UTF_8; public class CloudComputeService { private static final Logger LOG = LoggerFactory .getLogger(CloudComputeService.class); private final CloudComputeConfig mConfig; private final ComputeServiceContext mComputeServiceContext; private final ComputeService mComputeService; private final Template mTemplate; private final String mGroupTag; public CloudComputeService(final CloudComputeConfig config) { mConfig = config; mComputeServiceContext = initComputeServiceContext(config.getmProvider(), config.getIdentity(), config.getCredential()); mComputeService = mComputeServiceContext.getComputeService(); mTemplate = mComputeService.templateBuilder().hardwareId(config.getInstanceType()).imageId(config.getImageId()).build(); TemplateOptions options = mTemplate.getOptions(); // Set generic options options.blockOnPort(22, 60); options.userMetadata(config.getUserMetaData()); // Set provider options switch (config.getmProvider()) { case AWS: mGroupTag = String.format("group=%s", config.getGroupName()); options.as(AWSEC2TemplateOptions.class) .keyPair(config.getKeyPairName()) .securityGroupIds(config.getSecurityGroup()) .spotPrice(config.getMaxBid()) .tags(Collections.singletonList(mGroupTag)); break; case GCE: mGroupTag = config.getGroupName(); options.as(GoogleComputeEngineTemplateOptions.class) .tags(Arrays.asList(config.getGroupName(), config.getSecurityGroup())); // GCE firewall is set through instance tags break; default: mGroupTag = ""; } } private ComputeServiceContext initComputeServiceContext(CloudComputeConfig.CloudComputeProvider provider, String identity, String credential) { Properties overrides = new Properties(); overrides.put(ComputeServiceProperties.POLL_INITIAL_PERIOD, String.valueOf(60L * 1000L)); overrides.put(ComputeServiceProperties.POLL_MAX_PERIOD, String.valueOf(600L * 1000L)); overrides.put(Constants.PROPERTY_MAX_RETRIES, String.valueOf(60)); return ContextBuilder.newBuilder(provider.getmJcloudsId()) .credentials(identity, credential) .modules(ImmutableSet.of( new SshjSshClientModule(), new Log4JLoggingModule() )) .overrides(overrides) .buildView(ComputeServiceContext.class); } public Set<NodeMetadata> createNodes(int count) throws RunNodesException { Set<NodeMetadata> result = Sets.newHashSet(); result.addAll(mComputeService.createNodesInGroup(mConfig.getGroupName(), count, mTemplate)); return result; } static Predicate<ComputeMetadata> createFilterPTestPredicate(final String groupName, final String groupTag) { return new Predicate<ComputeMetadata>() { @Override public boolean apply(ComputeMetadata computeMetadata) { NodeMetadata nodeMetadata = (NodeMetadata) computeMetadata; return nodeMetadata.getStatus() == Status.RUNNING && isPTestHost(nodeMetadata); } private boolean isPTestHost(NodeMetadata node) { String result = "false non-ptest host"; if(groupName.equalsIgnoreCase(node.getGroup())) { result = "true due to group " + groupName; return true; } if(Strings.nullToEmpty(node.getName()).startsWith(groupName)) { result = "true due to name " + groupName; return true; } if(node.getTags().contains(groupTag)) { result = "true due to tag " + groupName; return true; } LOG.debug("Found node: " + node + ", Result: " + result); return false; } }; } public Set<NodeMetadata> listRunningNodes(){ Set<NodeMetadata> result = Sets.newHashSet(); result.addAll(mComputeService.listNodesDetailsMatching( createFilterPTestPredicate(mConfig.getGroupName(), mGroupTag))); return result; } public void destroyNode(String nodeId) { mComputeService.destroyNode(nodeId); } public void close() { mComputeServiceContext.close(); } public static class CloudComputeConfig { public enum CloudComputeProvider { AWS("aws-ec2"), GCE("google-compute-engine"); private final String mJcloudsId; CloudComputeProvider(String jcloudsId) { mJcloudsId = jcloudsId; } public String getmJcloudsId() { return mJcloudsId; } }; private final CloudComputeProvider mProvider; private String mIdentity; private String mCredential; private String mInstanceType; private String mImageId; private String mGroupName; private String mSecurityGroup; private String mKeyPairName; private Map<String, String> mUserMetaData; /** * JClouds requests on-demand instances when null */ private Float mMaxBid; public CloudComputeConfig(CloudComputeProvider provider) { mProvider = provider; } public void setCredentials(String identity, String credential) { mIdentity = identity; mCredential = credential; } public void setInstanceType(String instanceType) { mInstanceType = instanceType; } public void setImageId(String imageId) { mImageId = imageId; } public void setGroupName(String groupName) { mGroupName = groupName; } public void setSecurityGroup(String securityGroup) { mSecurityGroup = securityGroup; } public void setMaxBid(Float maxBid) { mMaxBid = maxBid; } public void setmKeyPairName(String keyPairName) { mKeyPairName = keyPairName; } public void setUserMetaData(Map<String, String> userMetaData) { mUserMetaData = userMetaData; } public CloudComputeProvider getmProvider() { return mProvider; } public String getIdentity() { return mIdentity; } public String getCredential() { return mCredential; } public String getInstanceType() { return mInstanceType; } public String getImageId() { return mImageId; } public String getGroupName() { return mGroupName; } public String getSecurityGroup() { return mSecurityGroup; } public Float getMaxBid() { return mMaxBid; } public String getKeyPairName() { return mKeyPairName; } public Map<String, String> getUserMetaData() { if (mUserMetaData == null) { return ImmutableMap.of(); } return mUserMetaData; } } public static Credentials getCredentialsFromJsonKeyFile(String filename) throws IOException { String fileContents = Files.toString(new File(filename), UTF_8); Supplier<Credentials> credentialSupplier = new GoogleCredentialsFromJson(fileContents); return credentialSupplier.get(); } }