mirror of https://github.com/apache/jclouds.git
first working integration between chef and the compute apis
This commit is contained in:
parent
64a52c0420
commit
8afc0a833e
|
@ -77,6 +77,12 @@
|
||||||
<artifactId>jclouds-compute</artifactId>
|
<artifactId>jclouds-compute</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>jclouds-jsch</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>jclouds-log4j</artifactId>
|
<artifactId>jclouds-log4j</artifactId>
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
(
|
|
||||||
cat <<'EOP'
|
|
||||||
@herefile@
|
|
||||||
EOP
|
|
||||||
) > @destination@
|
|
|
@ -21,27 +21,52 @@ package org.jclouds.chef.compute;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.collect.Sets.newHashSet;
|
import static com.google.common.collect.Sets.newHashSet;
|
||||||
|
import static org.jclouds.io.Payloads.newStringPayload;
|
||||||
|
import static org.jclouds.scriptbuilder.domain.Statements.createFile;
|
||||||
|
import static org.jclouds.scriptbuilder.domain.Statements.exec;
|
||||||
|
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jclouds.chef.ChefContext;
|
import org.jclouds.chef.ChefContext;
|
||||||
import org.jclouds.chef.ChefContextFactory;
|
import org.jclouds.chef.ChefContextFactory;
|
||||||
import org.jclouds.chef.ChefService;
|
import org.jclouds.compute.BaseComputeServiceLiveTest;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
import org.jclouds.compute.ComputeServiceContextFactory;
|
import org.jclouds.compute.ComputeServiceContextFactory;
|
||||||
|
import org.jclouds.compute.RunNodesException;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.compute.options.TemplateOptions;
|
||||||
|
import org.jclouds.compute.predicates.NodePredicates;
|
||||||
import org.jclouds.crypto.Pems;
|
import org.jclouds.crypto.Pems;
|
||||||
|
import org.jclouds.json.Json;
|
||||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||||
|
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||||
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
|
import org.jclouds.ssh.jsch.config.JschSshClientModule;
|
||||||
|
import org.jclouds.util.Utils;
|
||||||
import org.testng.annotations.AfterGroups;
|
import org.testng.annotations.AfterGroups;
|
||||||
import org.testng.annotations.BeforeGroups;
|
import org.testng.annotations.BeforeGroups;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import com.google.inject.Module;
|
import com.google.inject.Module;
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -54,9 +79,12 @@ public class ChefComputeServiceLiveTest {
|
||||||
private ChefContext chefContext;
|
private ChefContext chefContext;
|
||||||
private String tag;
|
private String tag;
|
||||||
private String clientName;
|
private String clientName;
|
||||||
|
private String chefEndpoint;
|
||||||
|
private Map<String, String> keyPair;
|
||||||
|
private Iterable<? extends NodeMetadata> nodes;
|
||||||
|
|
||||||
@BeforeGroups(groups = { "live" })
|
@BeforeGroups(groups = { "live" })
|
||||||
public void setupCompute() {
|
public void setupCompute() throws FileNotFoundException, IOException {
|
||||||
tag = System.getProperty("jclouds.compute.tag") != null ? System.getProperty("jclouds.compute.tag")
|
tag = System.getProperty("jclouds.compute.tag") != null ? System.getProperty("jclouds.compute.tag")
|
||||||
: "jcloudschef";
|
: "jcloudschef";
|
||||||
String computeProvider = checkNotNull(System.getProperty("jclouds.compute.provider"), "jclouds.compute.provider");
|
String computeProvider = checkNotNull(System.getProperty("jclouds.compute.provider"), "jclouds.compute.provider");
|
||||||
|
@ -68,12 +96,13 @@ public class ChefComputeServiceLiveTest {
|
||||||
String computeCredential = checkNotNull(System.getProperty("jclouds.compute.credential"),
|
String computeCredential = checkNotNull(System.getProperty("jclouds.compute.credential"),
|
||||||
"jclouds.compute.credential");
|
"jclouds.compute.credential");
|
||||||
computeContext = new ComputeServiceContextFactory().createContext(computeProvider, computeIdentity,
|
computeContext = new ComputeServiceContextFactory().createContext(computeProvider, computeIdentity,
|
||||||
computeCredential, ImmutableSet.of(new Log4JLoggingModule()), props);
|
computeCredential, ImmutableSet.of(new Log4JLoggingModule(), getSshModule()), props);
|
||||||
|
keyPair = BaseComputeServiceLiveTest.setupKeyPair();
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeGroups(groups = { "live" })
|
@BeforeGroups(groups = { "live" })
|
||||||
public void setupChef() throws IOException {
|
public void setupChef() throws IOException {
|
||||||
String chefEndpoint = checkNotNull(System.getProperty("jclouds.chef.endpoint"), "jclouds.chef.endpoint");
|
chefEndpoint = checkNotNull(System.getProperty("jclouds.chef.endpoint"), "jclouds.chef.endpoint");
|
||||||
String chefIdentity = checkNotNull(System.getProperty("jclouds.chef.identity"), "jclouds.chef.identity");
|
String chefIdentity = checkNotNull(System.getProperty("jclouds.chef.identity"), "jclouds.chef.identity");
|
||||||
String chefCredentialFile = System.getProperty("jclouds.chef.credential.pem");
|
String chefCredentialFile = System.getProperty("jclouds.chef.credential.pem");
|
||||||
if (chefCredentialFile == null || chefCredentialFile.equals(""))
|
if (chefCredentialFile == null || chefCredentialFile.equals(""))
|
||||||
|
@ -84,27 +113,83 @@ public class ChefComputeServiceLiveTest {
|
||||||
Charsets.UTF_8), ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
|
Charsets.UTF_8), ImmutableSet.<Module> of(new Log4JLoggingModule()), props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class InstallChefGems implements Statement {
|
||||||
|
|
||||||
|
public String render(OsFamily family) {
|
||||||
|
try {
|
||||||
|
return Utils.toStringAndClose(InstallChefGems.class.getClassLoader().getResourceAsStream(
|
||||||
|
"install-chef-gems.sh"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Throwables.propagate(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<String> functionDependecies(OsFamily family) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Module getSshModule() {
|
||||||
|
return new JschSshClientModule();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws IOException {
|
public void test() throws IOException, InterruptedException {
|
||||||
clientName = findNextClientName(chefContext, tag + "-%d");
|
clientName = findNextClientName(chefContext, tag + "-validator-%d");
|
||||||
String clientKey = Pems.pem(chefContext.getApi().createClient(clientName).getPrivateKey());
|
|
||||||
|
|
||||||
// herefile /etc/chef/client.rb
|
|
||||||
// log_level :info
|
|
||||||
// log_location STDOUT
|
|
||||||
// chef_server_url "@chef_server_url@"
|
|
||||||
|
|
||||||
// herefile /etc/chef/client.pem
|
|
||||||
// clientKey
|
|
||||||
// herefile /etc/chef/first-boot.json
|
|
||||||
// { "run_list": [ "recipe[apache]" ] }
|
|
||||||
|
|
||||||
// then run /usr/bin/chef-client -j /etc/chef/first-boot.json
|
|
||||||
|
|
||||||
System.out.println("created new client: " + clientName);
|
System.out.println("created new client: " + clientName);
|
||||||
|
|
||||||
computeContext.getComputeService().listNodes();
|
List<String> runList = ImmutableList.of("recipe[apache2]");
|
||||||
chefContext.getChefService().listNodesDetails();
|
Json json = computeContext.utils().json();
|
||||||
|
|
||||||
|
String clientKey = Pems.pem(chefContext.getApi().createClient(clientName).getPrivateKey());
|
||||||
|
|
||||||
|
Statement installChefGems = new InstallChefGems();
|
||||||
|
String chefConfigDir = "{root}etc{fs}chef";
|
||||||
|
Statement createChefConfigDir = exec("{md} " + chefConfigDir);
|
||||||
|
Statement createClientRb = createFile(chefConfigDir + "{fs}client.rb", ImmutableList.of("require 'rubygems'",
|
||||||
|
"require 'ohai'", "o = Ohai::System.new", "o.all_plugins", String.format(
|
||||||
|
"node_name \"%s-\" + o[:ipaddress]", tag), "log_level :info", "log_location STDOUT", String
|
||||||
|
.format("validation_client_name \"%s\"", clientName), String.format("chef_server_url \"%s\"",
|
||||||
|
chefEndpoint)));
|
||||||
|
|
||||||
|
Statement createValidationPem = createFile(chefConfigDir + "{fs}validation.pem", Splitter.on('\n').split(
|
||||||
|
clientKey));
|
||||||
|
String chefBootFile = chefConfigDir + "{fs}first-boot.json";
|
||||||
|
|
||||||
|
Statement createFirstBoot = createFile(chefBootFile, Collections.singleton(json.toJson(ImmutableMap
|
||||||
|
.<String, List<String>> of("run_list", runList), new TypeLiteral<Map<String, List<String>>>() {
|
||||||
|
}.getType())));
|
||||||
|
|
||||||
|
Statement runChef = exec("chef-client -j " + chefBootFile);
|
||||||
|
|
||||||
|
Statement bootstrapAndRunChef = newStatementList(installChefGems, createChefConfigDir, createClientRb,
|
||||||
|
createValidationPem, createFirstBoot, runChef);
|
||||||
|
|
||||||
|
String runScript = bootstrapAndRunChef.render(OsFamily.UNIX);
|
||||||
|
System.out.println(runScript);
|
||||||
|
|
||||||
|
TemplateOptions options = computeContext.getComputeService().templateOptions().//
|
||||||
|
installPrivateKey(newStringPayload(keyPair.get("private"))).//
|
||||||
|
authorizePublicKey(newStringPayload(keyPair.get("public"))).//
|
||||||
|
runScript(newStringPayload(runScript));
|
||||||
|
|
||||||
|
try {
|
||||||
|
nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, options);
|
||||||
|
} catch (RunNodesException e) {
|
||||||
|
nodes = Iterables.concat(e.getSuccessfulNodes(), e.getNodeErrors().keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (NodeMetadata node : nodes) {
|
||||||
|
URI uri = URI.create("http://" + Iterables.getLast(node.getPublicAddresses()));
|
||||||
|
InputStream content = computeContext.utils().http().get(uri);
|
||||||
|
String string = Utils.toStringAndClose(content);
|
||||||
|
assert string.indexOf("It works!") >= 0 : string;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String findNextClientName(ChefContext context, String pattern) {
|
private String findNextClientName(ChefContext context, String pattern) {
|
||||||
|
@ -122,13 +207,16 @@ public class ChefComputeServiceLiveTest {
|
||||||
|
|
||||||
@AfterGroups(groups = { "live" })
|
@AfterGroups(groups = { "live" })
|
||||||
public void teardownCompute() {
|
public void teardownCompute() {
|
||||||
if (computeContext != null)
|
if (computeContext != null) {
|
||||||
|
computeContext.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag));
|
||||||
computeContext.close();
|
computeContext.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterGroups(groups = { "live" })
|
@AfterGroups(groups = { "live" })
|
||||||
public void teardownChef() {
|
public void teardownChef() {
|
||||||
if (chefContext != null) {
|
if (chefContext != null) {
|
||||||
|
chefContext.getChefService().cleanupStaleNodesAndClients(tag + "-", 1);
|
||||||
if (clientName != null && chefContext.getApi().clientExists(clientName))
|
if (clientName != null && chefContext.getApi().clientExists(clientName))
|
||||||
chefContext.getApi().deleteClient(clientName);
|
chefContext.getApi().deleteClient(clientName);
|
||||||
chefContext.close();
|
chefContext.close();
|
||||||
|
|
|
@ -4,7 +4,8 @@ if [ ! -f /usr/bin/chef-client ]; then
|
||||||
mkdir -p /tmp/bootchef
|
mkdir -p /tmp/bootchef
|
||||||
(
|
(
|
||||||
cd /tmp/bootchef
|
cd /tmp/bootchef
|
||||||
curl http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz| tar -xzf -
|
wget http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz
|
||||||
|
tar xvf rubygems-1.3.6.tgz
|
||||||
cd rubygems-1.3.6
|
cd rubygems-1.3.6
|
||||||
ruby setup.rb
|
ruby setup.rb
|
||||||
cp /usr/bin/gem1.8 /usr/bin/gem
|
cp /usr/bin/gem1.8 /usr/bin/gem
|
|
@ -25,7 +25,27 @@
|
||||||
-->
|
-->
|
||||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
|
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
|
||||||
debug="false">
|
debug="false">
|
||||||
|
<!-- A time/date based rolling appender -->
|
||||||
|
<appender name="COMPUTEFILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||||
|
<param name="File" value="target/test-data/jclouds-compute.log" />
|
||||||
|
<param name="Append" value="true" />
|
||||||
|
|
||||||
|
<!-- Rollover at midnight each day -->
|
||||||
|
<param name="DatePattern" value="'.'yyyy-MM-dd" />
|
||||||
|
|
||||||
|
<param name="Threshold" value="TRACE" />
|
||||||
|
|
||||||
|
<layout class="org.apache.log4j.PatternLayout">
|
||||||
|
<!-- The default pattern: Date Priority [Category] Message\n -->
|
||||||
|
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The full pattern: Date MS Priority [Category]
|
||||||
|
(Thread:NDC) Message\n <param name="ConversionPattern"
|
||||||
|
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
|
||||||
|
-->
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
<!-- A time/date based rolling appender -->
|
<!-- A time/date based rolling appender -->
|
||||||
<appender name="SSHFILE" class="org.apache.log4j.DailyRollingFileAppender">
|
<appender name="SSHFILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||||
<param name="File" value="target/test-data/jclouds-ssh.log" />
|
<param name="File" value="target/test-data/jclouds-ssh.log" />
|
||||||
|
@ -113,6 +133,9 @@
|
||||||
-->
|
-->
|
||||||
</layout>
|
</layout>
|
||||||
</appender>
|
</appender>
|
||||||
|
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
|
||||||
|
<appender-ref ref="COMPUTEFILE" />
|
||||||
|
</appender>
|
||||||
<appender name="ASYNCCHEF" class="org.apache.log4j.AsyncAppender">
|
<appender name="ASYNCCHEF" class="org.apache.log4j.AsyncAppender">
|
||||||
<appender-ref ref="CHEFFILE" />
|
<appender-ref ref="CHEFFILE" />
|
||||||
</appender>
|
</appender>
|
||||||
|
@ -156,6 +179,11 @@
|
||||||
<priority value="DEBUG" />
|
<priority value="DEBUG" />
|
||||||
<appender-ref ref="ASYNCSSH" />
|
<appender-ref ref="ASYNCSSH" />
|
||||||
</category>
|
</category>
|
||||||
|
|
||||||
|
<category name="jclouds.compute">
|
||||||
|
<priority value="TRACE" />
|
||||||
|
<appender-ref ref="ASYNCCOMPUTE" />
|
||||||
|
</category>
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
<category name="jclouds.wire"> <priority value="DEBUG" />
|
<category name="jclouds.wire"> <priority value="DEBUG" />
|
||||||
|
|
Loading…
Reference in New Issue