Updated Branches: refs/heads/master 15e8825ad -> c96412771
Example of creating a server with a key pair Project: http://git-wip-us.apache.org/repos/asf/jclouds-examples/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-examples/commit/c9641277 Tree: http://git-wip-us.apache.org/repos/asf/jclouds-examples/tree/c9641277 Diff: http://git-wip-us.apache.org/repos/asf/jclouds-examples/diff/c9641277 Branch: refs/heads/master Commit: c9641277135773d9780e01f0180c63823e2081ed Parents: 15e8825 Author: Everett Toews <[email protected]> Authored: Sun Jan 12 22:50:20 2014 -0600 Committer: Everett Toews <[email protected]> Committed: Mon Jan 13 11:30:44 2014 -0600 ---------------------------------------------------------------------- .../jclouds/examples/rackspace/SmokeTest.java | 1 + .../cloudservers/CreateServerWithKeyPair.java | 230 +++++++++++++++++++ 2 files changed, 231 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/c9641277/rackspace/src/main/java/org/jclouds/examples/rackspace/SmokeTest.java ---------------------------------------------------------------------- diff --git a/rackspace/src/main/java/org/jclouds/examples/rackspace/SmokeTest.java b/rackspace/src/main/java/org/jclouds/examples/rackspace/SmokeTest.java index 97a6a73..678d7b2 100644 --- a/rackspace/src/main/java/org/jclouds/examples/rackspace/SmokeTest.java +++ b/rackspace/src/main/java/org/jclouds/examples/rackspace/SmokeTest.java @@ -56,6 +56,7 @@ public class SmokeTest { CloudServersPublish.main(args); CreateServer.main(args); + CreateServerWithKeyPair.main(args); ListServersWithFiltering.main(args); ServerMetadata.main(args); DeleteServer.main(args); http://git-wip-us.apache.org/repos/asf/jclouds-examples/blob/c9641277/rackspace/src/main/java/org/jclouds/examples/rackspace/cloudservers/CreateServerWithKeyPair.java ---------------------------------------------------------------------- diff --git a/rackspace/src/main/java/org/jclouds/examples/rackspace/cloudservers/CreateServerWithKeyPair.java b/rackspace/src/main/java/org/jclouds/examples/rackspace/cloudservers/CreateServerWithKeyPair.java new file mode 100644 index 0000000..fa9d643 --- /dev/null +++ b/rackspace/src/main/java/org/jclouds/examples/rackspace/cloudservers/CreateServerWithKeyPair.java @@ -0,0 +1,230 @@ +/* + * 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.jclouds.examples.rackspace.cloudservers; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.io.Closeables; +import com.google.common.io.Files; +import com.google.inject.Module; +import org.jclouds.ContextBuilder; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.options.RunScriptOptions; +import org.jclouds.openstack.nova.v2_0.NovaApi; +import org.jclouds.openstack.nova.v2_0.NovaAsyncApi; +import org.jclouds.openstack.nova.v2_0.compute.options.NovaTemplateOptions; +import org.jclouds.openstack.nova.v2_0.domain.KeyPair; +import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndId; +import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi; +import org.jclouds.rest.RestContext; +import org.jclouds.scriptbuilder.ScriptBuilder; +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.sshj.config.SshjSshClientModule; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.TimeoutException; + +import static com.google.common.base.Charsets.UTF_8; +import static org.jclouds.compute.config.ComputeServiceProperties.POLL_INITIAL_PERIOD; +import static org.jclouds.compute.config.ComputeServiceProperties.POLL_MAX_PERIOD; +import static org.jclouds.examples.rackspace.cloudservers.Constants.NAME; +import static org.jclouds.examples.rackspace.cloudservers.Constants.POLL_PERIOD_TWENTY_SECONDS; +import static org.jclouds.examples.rackspace.cloudservers.Constants.PROVIDER; +import static org.jclouds.examples.rackspace.cloudservers.Constants.ZONE; +import static org.jclouds.scriptbuilder.domain.Statements.exec; + +/** + * Create a public key in the cloud and write the private key file to the local working directory. The public key and + * private key together are known as a key pair (see http://en.wikipedia.org/wiki/Public-key_cryptography). This + * is a security feature that allows you to login to a server using a private key file. + * + * Create a server with the public key, use the private key to login to it, and disable password authentication. + */ +public class CreateServerWithKeyPair implements Closeable { + private final ComputeService computeService; + private final RestContext<NovaApi, NovaAsyncApi> novaContext; + + private final File keyPairFile = new File(NAME + ".pem"); + + /** + * To get a username and API key see + * http://jclouds.apache.org/documentation/quickstart/rackspace/ + * + * The first argument (args[0]) must be your username + * The second argument (args[1]) must be your API key + */ + public static void main(String[] args) throws IOException { + System.out.format("CreateServerWithKeyPair%n"); + + CreateServerWithKeyPair createServerWithKeyPair = new CreateServerWithKeyPair(args[0], args[1]); + NodeMetadata node; + + try { + createServerWithKeyPair.detectKeyPairExtension(); + KeyPair keyPair = createServerWithKeyPair.createKeyPair(); + node = createServerWithKeyPair.createServer(keyPair); + createServerWithKeyPair.disablePasswordAuthentication(node); + createServerWithKeyPair.deleteKeyPair(keyPair); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + createServerWithKeyPair.close(); + } + } + + public CreateServerWithKeyPair(String username, String apiKey) { + Iterable<Module> modules = ImmutableSet.<Module> of(new SshjSshClientModule()); + + // These properties control how often jclouds polls for a status update + Properties overrides = new Properties(); + overrides.setProperty(POLL_INITIAL_PERIOD, POLL_PERIOD_TWENTY_SECONDS); + overrides.setProperty(POLL_MAX_PERIOD, POLL_PERIOD_TWENTY_SECONDS); + + ComputeServiceContext context = ContextBuilder.newBuilder(PROVIDER) + .credentials(username, apiKey) + .overrides(overrides) + .modules(modules) + .buildView(ComputeServiceContext.class); + + computeService = context.getComputeService(); + novaContext = context.unwrap(); + } + + /** + * Detect that the OpenStack Key Pair Extension is installed on the Rackspace Cloud. + * + * This method is not necessary and is here for demonstration purposes only. + */ + private void detectKeyPairExtension() { + Optional<? extends KeyPairApi> keyPairApiExtension = novaContext.getApi().getKeyPairExtensionForZone(ZONE); + + if (keyPairApiExtension.isPresent()) { + System.out.format(" Key Pair Extension Present%n"); + + KeyPairApi keyPairApi = keyPairApiExtension.get(); + + for (KeyPair keyPair: keyPairApi.list()) { + System.out.format(" %s%n", keyPair.getName()); + } + } + } + + /** + * Create a public key in the cloud and write the private key file to the local working directory. + */ + private KeyPair createKeyPair() throws IOException { + System.out.format(" Create Key Pair%n"); + + KeyPairApi keyPairApi = novaContext.getApi().getKeyPairExtensionForZone(ZONE).get(); + KeyPair keyPair = keyPairApi.create(NAME); + + Files.write(keyPair.getPrivateKey(), keyPairFile, UTF_8); + + System.out.format(" Wrote %s%n", keyPairFile.getAbsolutePath()); + + return keyPair; + } + + /** + * Create a server with the key pair. + */ + private NodeMetadata createServer(KeyPair keyPair) throws RunNodesException, TimeoutException { + System.out.format(" Create Server%n"); + + NovaTemplateOptions options = NovaTemplateOptions.Builder.keyPairName(keyPair.getName()); + + ZoneAndId zoneAndId = ZoneAndId.fromZoneAndId(ZONE, "performance1-1"); + Template template = computeService.templateBuilder() + .locationId(ZONE) + .osDescriptionMatches(".*Ubuntu 12.04.*") + .hardwareId(zoneAndId.slashEncode()) + .options(options) + .build(); + + // This method will continue to poll for the server status and won't return until this server is ACTIVE + // If you want to know what's happening during the polling, enable logging. + // See /jclouds-example/rackspace/src/main/java/org/jclouds/examples/rackspace/Logging.java + Set<? extends NodeMetadata> nodes = computeService.createNodesInGroup(NAME, 1, template); + NodeMetadata node = Iterables.getOnlyElement(nodes); + + System.out.format(" %s%n", node); + + return node; + } + + /** + * If desired, you can disable password authentication for the server because we can use a private key to SSH in. + * + * No need to explicitly include the private key with running the script on the node. jclouds is already aware + * of the private key when the node was created earlier. + */ + private void disablePasswordAuthentication(NodeMetadata node) throws TimeoutException { + System.out.format(" Disable Password Authentication%n"); + + String script = new ScriptBuilder() + .addStatement(exec("sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config")) + .addStatement(exec("service ssh restart")) + .render(OsFamily.UNIX); + + RunScriptOptions options = RunScriptOptions.Builder + .blockOnPort(22, 10) + .blockOnComplete(true); + + computeService.runScriptOnNode(node.getId(), script, options); + + String publicAddress = Iterables.getOnlyElement(node.getPublicAddresses()); + + System.out.format(" ssh -i %s root@%s%n", keyPairFile.getAbsolutePath(), publicAddress); + } + + /** + * Delete the public key in the cloud and the local private key. + */ + private void deleteKeyPair(KeyPair keyPair) { + System.out.format(" Delete Key Pair%n"); + + KeyPairApi keyPairApi = novaContext.getApi().getKeyPairExtensionForZone(ZONE).get(); + keyPairApi.delete(keyPair.getName()); + + if (keyPairFile.delete()) { + System.out.format(" Deleted %s%n", keyPairFile.getAbsolutePath()); + } + else { + System.err.format(" Could not delete %s%n", keyPairFile.getAbsolutePath()); + } + } + + /** + * Always close your service when you're done with it. + */ + public void close() throws IOException { + Closeables.close(computeService.getContext(), true); + } +}
