/* * 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.brooklyn.location.jclouds; import static org.testng.Assert.assertNotNull; import java.io.File; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Properties; import java.util.Set; import java.util.UUID; import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.util.text.Identifiers; import org.jclouds.Constants; import org.jclouds.ContextBuilder; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.domain.Credentials; import org.jclouds.domain.LoginCredentials; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.sshj.config.SshjSshClientModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.Test; import com.google.common.base.Throwables; import com.google.common.collect.Iterables; import com.google.common.io.Files; public class StandaloneJcloudsLiveTest { // FIXME Why do this? // Were we seeing bugs in jclouds for which this was easier to debug and report // Is it because testProvisioningVmWithCustomUsername is disabled and not working? public static final Logger LOG = LoggerFactory.getLogger(StandaloneJcloudsLiveTest.class); private static final String PROVIDER = AbstractJcloudsLiveTest.AWS_EC2_PROVIDER; private static final String REGION = AbstractJcloudsLiveTest.AWS_EC2_USEAST_REGION_NAME; private static final String PRIVATE_IMAGE_ID = "us-east-1/ami-f95cf390"; static BrooklynProperties globals = BrooklynProperties.Factory.newDefault(); String identity = globals.getFirst("brooklyn.location.jclouds.aws-ec2.identity"); String credential = globals.getFirst("brooklyn.location.jclouds.aws-ec2.credential"); @Test(enabled=false, groups={"WIP","Live"}) public void createVm() { String groupId = "mygroup-"+System.getProperty("user.name")+"-"+UUID.randomUUID().toString(); Properties properties = new Properties(); properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, Boolean.toString(true)); properties.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, Boolean.toString(true)); // handy to list all images... but very slow! // properties.setProperty(AWSEC2Constants.PROPERTY_EC2_AMI_QUERY, "state=available;image-type=machine"); ComputeServiceContext computeServiceContext = ContextBuilder.newBuilder(PROVIDER). modules(Arrays.asList(new SshjSshClientModule(), new SLF4JLoggingModule())). credentials(identity, credential). overrides(properties). build(ComputeServiceContext.class); final ComputeService computeService = computeServiceContext.getComputeService(); NodeMetadata node = null; try { LOG.info("Creating VM for "+identity); TemplateBuilder templateBuilder = computeService.templateBuilder(); templateBuilder.locationId(REGION); Template template = templateBuilder.build(); Set<? extends NodeMetadata> nodes = computeService.createNodesInGroup(groupId, 1, template); node = Iterables.getOnlyElement(nodes, null); if (node == null) throw new IllegalStateException("No nodes returned"); assertNotNull(node.getOperatingSystem()); Credentials nodeCredentials = node.getCredentials(); final LoginCredentials expectedCredentials = LoginCredentials.fromCredentials(nodeCredentials); LOG.info("Started VM, waiting for it to be sshable"); boolean reachable = false; for (int i=0; i<120; i++) { try { Statement statement = Statements.newStatementList(Statements.exec("date")); ExecResponse response = computeService.runScriptOnNode(node.getId(), statement, RunScriptOptions.Builder.overrideLoginCredentials(expectedCredentials)); if (response.getExitStatus() == 0) { LOG.info("ssh 'date' succeeded"); reachable = true; break; } LOG.info("ssh 'date' failed, exit "+response.getExitStatus()+", but still in retry loop"); } catch (Exception e) { if (i<120) LOG.info("ssh 'date' failed, but still in retry loop: "+e); else { LOG.error("ssh 'date' failed after timeout: "+e, e); Throwables.propagate(e); } } Thread.sleep(1000); } if (!reachable) { throw new IllegalStateException("SSH failed, never reachable"); } } catch (RunNodesException e) { if (e.getNodeErrors().size() > 0) { node = Iterables.get(e.getNodeErrors().keySet(), 0); } LOG.error("Failed to start VM: "+e, e); throw Throwables.propagate(e); } catch (Exception e) { LOG.error("Failed to start VM: "+e, e); throw Throwables.propagate(e); } finally { LOG.info("Now destroying VM: "+node); computeService.destroyNode( node.getId() ); computeService.getContext().close(); } } @Test(enabled=false, groups={"WIP","Live"}) public void createVmWithAdminUser() { String groupId = "mygroup-"+System.getProperty("user.name")+"-"+UUID.randomUUID().toString(); Properties properties = new Properties(); properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, Boolean.toString(true)); properties.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, Boolean.toString(true)); ComputeServiceContext computeServiceContext = ContextBuilder.newBuilder(PROVIDER). modules(Arrays.asList(new SshjSshClientModule(), new SLF4JLoggingModule())). credentials(identity, credential). overrides(properties). build(ComputeServiceContext.class); final ComputeService computeService = computeServiceContext.getComputeService(); NodeMetadata node = null; try { LOG.info("Creating VM for "+identity); String myPubKey = Files.toString(new File(System.getProperty("user.home")+"/.ssh/aws-id_rsa.pub"), Charset.defaultCharset()); String myPrivKey = Files.toString(new File(System.getProperty("user.home")+"/.ssh/aws-id_rsa"), Charset.defaultCharset()); TemplateBuilder templateBuilder = computeService.templateBuilder(); templateBuilder.locationId(REGION); TemplateOptions opts = new TemplateOptions(); // templateBuilder.imageId("us-east-1/ami-2342a94a"); //rightscale // either use above, or below templateBuilder.imageId(PRIVATE_IMAGE_ID); //private one (to test when user isn't autodetected) opts.overrideLoginUser("ec2-user"); AdminAccess.Builder adminBuilder = AdminAccess.builder(). adminUsername("bob"). grantSudoToAdminUser(true). authorizeAdminPublicKey(true).adminPublicKey(myPubKey). // items below aren't wanted but values for some are required otherwise AdminAccess uses all defaults lockSsh(true).adminPassword(Identifiers.makeRandomId(12)). resetLoginPassword(false).loginPassword(Identifiers.makeRandomId(12)). installAdminPrivateKey(false).adminPrivateKey("ignored"); opts.runScript(adminBuilder.build()); templateBuilder.options(opts); Template template = templateBuilder.build(); Set<? extends NodeMetadata> nodes = computeService.createNodesInGroup(groupId, 1, template); node = Iterables.getOnlyElement(nodes, null); if (node == null) throw new IllegalStateException("No nodes returned"); LOG.info("Started VM, waiting for it to be sshable on "+node.getPublicAddresses()); final LoginCredentials crds = // node.getCredentials(); LoginCredentials.builder().user("bob").privateKey(myPrivKey).build(); boolean reachable = false; for (int i=0; i<120; i++) { try { Statement statement = Statements.newStatementList(Statements.exec("date")); ExecResponse response = computeService.runScriptOnNode(node.getId(), statement, RunScriptOptions.Builder.overrideLoginCredentials(crds)); if (response.getExitStatus() == 0) { LOG.info("ssh 'date' succeeded"); reachable = true; break; } LOG.info("ssh 'date' failed, exit "+response.getExitStatus()+", but still in retry loop"); } catch (Exception e) { if (i<120) LOG.info("ssh 'date' failed, but still in retry loop: "+e); else { LOG.error("ssh 'date' failed after timeout: "+e, e); Throwables.propagate(e); } } Thread.sleep(1000); } if (!reachable) { throw new IllegalStateException("SSH failed, never reachable"); } } catch (RunNodesException e) { if (e.getNodeErrors().size() > 0) { node = Iterables.get(e.getNodeErrors().keySet(), 0); } LOG.error("Failed to start VM: "+e, e); throw Throwables.propagate(e); } catch (Exception e) { LOG.error("Failed to start VM: "+e, e); throw Throwables.propagate(e); } finally { LOG.info("Now destroying VM: "+node); computeService.destroyNode( node.getId() ); computeService.getContext().close(); } } }