mirror of https://github.com/apache/jclouds.git
Issue 191: added chef bootstrap
This commit is contained in:
parent
8afc0a833e
commit
0b11e7d652
|
@ -20,11 +20,7 @@
|
|||
package org.jclouds.chef.compute;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
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 static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -32,25 +28,18 @@ 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.Set;
|
||||
|
||||
import org.jclouds.chef.ChefContext;
|
||||
import org.jclouds.chef.ChefContextFactory;
|
||||
import org.jclouds.compute.BaseComputeServiceLiveTest;
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
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.json.Json;
|
||||
import org.jclouds.io.Payload;
|
||||
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;
|
||||
|
@ -58,15 +47,10 @@ import org.testng.annotations.BeforeGroups;
|
|||
import org.testng.annotations.Test;
|
||||
|
||||
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.Iterables;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -80,7 +64,6 @@ public class ChefComputeServiceLiveTest {
|
|||
private String tag;
|
||||
private String clientName;
|
||||
private String chefEndpoint;
|
||||
private Map<String, String> keyPair;
|
||||
private Iterable<? extends NodeMetadata> nodes;
|
||||
|
||||
@BeforeGroups(groups = { "live" })
|
||||
|
@ -97,7 +80,6 @@ public class ChefComputeServiceLiveTest {
|
|||
"jclouds.compute.credential");
|
||||
computeContext = new ComputeServiceContextFactory().createContext(computeProvider, computeIdentity,
|
||||
computeCredential, ImmutableSet.of(new Log4JLoggingModule(), getSshModule()), props);
|
||||
keyPair = BaseComputeServiceLiveTest.setupKeyPair();
|
||||
}
|
||||
|
||||
@BeforeGroups(groups = { "live" })
|
||||
|
@ -113,69 +95,21 @@ public class ChefComputeServiceLiveTest {
|
|||
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
|
||||
public void test() throws IOException, InterruptedException {
|
||||
clientName = findNextClientName(chefContext, tag + "-validator-%d");
|
||||
public void testCanUpdateRunList() throws IOException {
|
||||
chefContext.getChefService().updateRunListForTag(Collections.singleton("recipe[apache2]"), tag);
|
||||
assertEquals(chefContext.getChefService().getRunListForTag(tag), Collections.singleton("recipe[apache2]"));
|
||||
}
|
||||
|
||||
System.out.println("created new client: " + clientName);
|
||||
@Test(dependsOnMethods = "testCanUpdateRunList")
|
||||
public void testRunNodesWithBootstrap() throws IOException {
|
||||
|
||||
List<String> runList = ImmutableList.of("recipe[apache2]");
|
||||
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));
|
||||
Payload bootstrap = chefContext.getChefService().createClientAndBootstrapScriptForTag(tag);
|
||||
TemplateOptions options = computeContext.getComputeService().templateOptions().runScript(bootstrap);
|
||||
|
||||
try {
|
||||
nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, options);
|
||||
|
@ -192,19 +126,6 @@ public class ChefComputeServiceLiveTest {
|
|||
|
||||
}
|
||||
|
||||
private String findNextClientName(ChefContext context, String pattern) {
|
||||
Set<String> nodes = context.getApi().listClients();
|
||||
String nodeName;
|
||||
Set<String> names = newHashSet(nodes);
|
||||
int index = 0;
|
||||
while (true) {
|
||||
nodeName = String.format(pattern, index++);
|
||||
if (!names.contains(nodeName))
|
||||
break;
|
||||
}
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
@AfterGroups(groups = { "live" })
|
||||
public void teardownCompute() {
|
||||
if (computeContext != null) {
|
||||
|
|
|
@ -1,107 +1,120 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010 Cloud Conscious, LLC <info@cloudconscious.com>
|
||||
<!--
|
||||
Copyright (C) 2010 Cloud Conscious, LLC
|
||||
<info@cloudconscious.com>
|
||||
|
||||
====================================================================
|
||||
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
|
||||
====================================================================
|
||||
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.html 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.
|
||||
====================================================================
|
||||
-->
|
||||
http://www.apache.org/licenses/LICENSE-2.0.html 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.
|
||||
====================================================================
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-chef-project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-chef</artifactId>
|
||||
<name>jclouds Chef core</name>
|
||||
<description>jclouds components to access Chef</description>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-chef-project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-chef</artifactId>
|
||||
<name>jclouds Chef core</name>
|
||||
<description>jclouds components to access Chef</description>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/chef</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/chef</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/chef</url>
|
||||
</scm>
|
||||
<scm>
|
||||
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/chef</connection>
|
||||
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/chef</developerConnection>
|
||||
<url>http://jclouds.googlecode.com/svn/trunk/chef</url>
|
||||
</scm>
|
||||
|
||||
<!-- bootstrapping: need to fetch the project POM -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jclouds-googlecode-deploy</id>
|
||||
<url>http://jclouds.googlecode.com/svn/repo</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jclouds-rimu-snapshots-nexus</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<!-- bootstrapping: need to fetch the project POM -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jclouds-googlecode-deploy</id>
|
||||
<url>http://jclouds.googlecode.com/svn/repo</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jclouds-rimu-snapshots-nexus</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<properties>
|
||||
<jclouds.chef.identity>chef-validator</jclouds.chef.identity>
|
||||
<jclouds.chef.rsa-key>/etc/chef/validation.pem</jclouds.chef.rsa-key>
|
||||
<jclouds.chef.endpoint>http://localhost:4000</jclouds.chef.endpoint>
|
||||
<jclouds.test.identity>${jclouds.chef.identity}</jclouds.test.identity>
|
||||
<jclouds.test.credential>${jclouds.chef.rsa-key}</jclouds.test.credential>
|
||||
<jclouds.test.endpoint>${jclouds.chef.endpoint}</jclouds.test.endpoint>
|
||||
</properties>
|
||||
<properties>
|
||||
<jclouds.chef.identity>chef-validator</jclouds.chef.identity>
|
||||
<jclouds.chef.rsa-key>/etc/chef/validation.pem</jclouds.chef.rsa-key>
|
||||
<jclouds.chef.endpoint>http://localhost:4000</jclouds.chef.endpoint>
|
||||
<jclouds.test.identity>${jclouds.chef.identity}</jclouds.test.identity>
|
||||
<jclouds.test.credential>${jclouds.chef.rsa-key}</jclouds.test.credential>
|
||||
<jclouds.test.endpoint>${jclouds.chef.endpoint}</jclouds.test.endpoint>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.14</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-log4j</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.danlarkin</groupId>
|
||||
<artifactId>clojure-json</artifactId>
|
||||
<version>1.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- for transient chef provider -->
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-blobstore</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- only required for Pems.java and only writing a private key file -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15</artifactId>
|
||||
<version>1.44</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-scriptbuilder</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.14</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-log4j</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.danlarkin</groupId>
|
||||
<artifactId>clojure-json</artifactId>
|
||||
<version>1.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- for transient chef provider -->
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>jclouds-blobstore</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -131,6 +131,24 @@ unit testing"
|
|||
([#^ChefService chef]
|
||||
(seq (.listNodesDetails chef))))
|
||||
|
||||
(defn update-run-list
|
||||
"Updates the run-list associated with a tag"
|
||||
([run-list tag] (update-run-list run-list tag *chef*))
|
||||
([run-list tag #^ChefService chef]
|
||||
(.updateRunListForTag chef run-list tag)))
|
||||
|
||||
(defn run-list
|
||||
"Retrieves the run-list associated with a tag"
|
||||
([tag] (run-list tag *chef*))
|
||||
([tag #^ChefService chef]
|
||||
(seq (.getRunListForTag chef tag))))
|
||||
|
||||
(defn create-bootstrap
|
||||
"creates a client and bootstrap script associated with a tag"
|
||||
([tag] (create-bootstrap tag *chef*))
|
||||
([tag #^ChefService chef]
|
||||
(.createClientAndBootstrapScriptForTag chef tag)))
|
||||
|
||||
(defn databags
|
||||
"Retrieve the names of the existing data bags in your chef server."
|
||||
([] (databags *chef*))
|
||||
|
|
|
@ -21,10 +21,12 @@ package org.jclouds.chef;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.jclouds.chef.domain.Node;
|
||||
import org.jclouds.chef.internal.BaseChefService;
|
||||
import org.jclouds.io.Payload;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
@ -56,6 +58,43 @@ public interface ChefService {
|
|||
*/
|
||||
Node createNodeAndPopulateAutomaticAttributes(String nodeName, Iterable<String> runList);
|
||||
|
||||
/**
|
||||
* Creates all steps necessary to bootstrap and run the chef client.
|
||||
*
|
||||
* @param tag
|
||||
* corresponds to a configured
|
||||
* {@link org.jclouds.chef.reference.ChefConstants#CHEF_BOOTSTRAP_DATABAG databag}
|
||||
* where run_list and other information are stored
|
||||
* @return boot script
|
||||
* @see #updateRunListForTag
|
||||
*/
|
||||
Payload createClientAndBootstrapScriptForTag(String tag);
|
||||
|
||||
/**
|
||||
* assigns a run list to all nodes bootstrapped with a certain tag
|
||||
*
|
||||
* @param runList
|
||||
* list of recipes or roles to assign. syntax is {@code recipe[name]} and {@code
|
||||
* role[name]}
|
||||
*
|
||||
* @param tag
|
||||
* corresponds to a configured
|
||||
* {@link org.jclouds.chef.reference.ChefConstants#CHEF_BOOTSTRAP_DATABAG databag}
|
||||
* where run_list and other information are stored
|
||||
* @see #makeChefClientBootstrapScriptForTag
|
||||
*/
|
||||
void updateRunListForTag(Iterable<String> runList, String tag);
|
||||
|
||||
/**
|
||||
* @param tag
|
||||
* corresponds to a configured
|
||||
* {@link org.jclouds.chef.reference.ChefConstants#CHEF_BOOTSTRAP_DATABAG databag}
|
||||
* where run_list and other information are stored
|
||||
* @return run list for all nodes bootstrapped with a certain tag
|
||||
* @see #updateRunListForTag
|
||||
*/
|
||||
List<String> getRunListForTag(String tag);
|
||||
|
||||
void deleteAllNodesInList(Iterable<String> names);
|
||||
|
||||
Iterable<? extends Node> listNodesDetails();
|
||||
|
@ -63,7 +102,7 @@ public interface ChefService {
|
|||
Iterable<? extends Node> listNodesDetailsMatching(Predicate<String> nodeNameSelector);
|
||||
|
||||
Iterable<? extends Node> listNodesNamed(Iterable<String> names);
|
||||
|
||||
|
||||
void deleteAllClientsInList(Iterable<String> names);
|
||||
|
||||
Iterable<? extends Client> listClientsDetails();
|
||||
|
|
|
@ -65,7 +65,7 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
|
|||
}
|
||||
|
||||
protected BaseChefRestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
|
||||
Map<Class<?>, Class<?>> delegates) {
|
||||
Map<Class<?>, Class<?>> delegates) {
|
||||
super(syncClientType, asyncClientType, delegates);
|
||||
}
|
||||
|
||||
|
@ -91,10 +91,10 @@ public class BaseChefRestClientModule<S, A> extends RestClientModule<S, A> {
|
|||
@Provides
|
||||
@Singleton
|
||||
public PrivateKey provideKey(Crypto crypto, @Named(PROPERTY_CREDENTIAL) String pem) throws InvalidKeySpecException,
|
||||
IOException {
|
||||
IOException {
|
||||
return crypto.rsaKeyFactory().generatePrivate(Pems.privateKeySpec(InputSuppliers.of(pem)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void bindErrorHandlers() {
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ChefErrorHandler.class);
|
||||
|
|
|
@ -19,10 +19,24 @@
|
|||
|
||||
package org.jclouds.chef.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.ChefAsyncClient;
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.jclouds.chef.functions.ClientForTag;
|
||||
import org.jclouds.chef.functions.RunListForTag;
|
||||
import org.jclouds.chef.statements.InstallChefGems;
|
||||
import org.jclouds.http.RequiresHttp;
|
||||
import org.jclouds.rest.ConfiguresRestClient;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
/**
|
||||
* Configures the Chef connection.
|
||||
|
@ -37,4 +51,22 @@ public class ChefRestClientModule extends BaseChefRestClientModule<ChefClient, C
|
|||
super(ChefClient.class, ChefAsyncClient.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Map<String, List<String>> runListForTag(RunListForTag runListForTag) {
|
||||
return new MapMaker().makeComputingMap(runListForTag);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Map<String, Client> tagToClient(ClientForTag tagToClient) {
|
||||
return new MapMaker().makeComputingMap(tagToClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(Statement.class).annotatedWith(Names.named("installChefGems")).to(InstallChefGems.class);
|
||||
super.configure();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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 org.jclouds.chef.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.domain.Client;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
*
|
||||
* Generates a client relevant for a particular tag
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class ClientForTag implements Function<String, Client> {
|
||||
private final ChefClient chefClient;
|
||||
|
||||
@Inject
|
||||
public ClientForTag(ChefClient chefClient) {
|
||||
this.chefClient = checkNotNull(chefClient, "chefClient");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Client apply(String from) {
|
||||
String clientName = findNextClientName(chefClient.listClients(), from + "-validator-%02d");
|
||||
Client client = chefClient.createClient(clientName);
|
||||
// response from create only includes the key
|
||||
return new Client(null, null, clientName, clientName, false, client.getPrivateKey());
|
||||
}
|
||||
|
||||
private static String findNextClientName(Set<String> clients, String pattern) {
|
||||
String clientName;
|
||||
Set<String> names = newHashSet(clients);
|
||||
int index = 0;
|
||||
while (true) {
|
||||
clientName = String.format(pattern,index++);
|
||||
if (!names.contains(clientName))
|
||||
break;
|
||||
}
|
||||
return clientName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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 org.jclouds.chef.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.jclouds.chef.reference.ChefConstants.CHEF_BOOTSTRAP_DATABAG;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.domain.DatabagItem;
|
||||
import org.jclouds.json.Json;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves the run-list for a specific tag
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class RunListForTag implements Function<String, List<String>> {
|
||||
public static final Type RUN_LIST_TYPE = new TypeLiteral<Map<String, List<String>>>() {
|
||||
}.getType();
|
||||
private final ChefClient client;
|
||||
private final Json json;
|
||||
private final String databag;
|
||||
|
||||
@Inject
|
||||
public RunListForTag(@Named(CHEF_BOOTSTRAP_DATABAG) String databag, ChefClient client, Json json) {
|
||||
this.databag = checkNotNull(databag, "databag");
|
||||
this.client = checkNotNull(client, "client");
|
||||
this.json = checkNotNull(json, "json");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<String> apply(String from) {
|
||||
DatabagItem list = client.getDatabagItem(databag, from);
|
||||
checkState(list != null, "databag item %s/%s not found", databag, from);
|
||||
return ((Map<String, List<String>>) json.fromJson(list.toString(), RUN_LIST_TYPE)).get("run_list");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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 org.jclouds.chef.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
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.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.jclouds.crypto.Pems;
|
||||
import org.jclouds.io.Payload;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.rest.annotations.Provider;
|
||||
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
*
|
||||
* Generates a bootstrap script relevant for a particular tag
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class TagToBootScript implements Function<String, Payload> {
|
||||
@VisibleForTesting
|
||||
static final Type RUN_LIST_TYPE = new TypeLiteral<Map<String, List<String>>>() {
|
||||
}.getType();
|
||||
private final URI endpoint;
|
||||
private final Json json;
|
||||
private final Map<String, Client> tagToClient;
|
||||
private final Map<String, List<String>> runListForTag;
|
||||
private final Statement installChefGems;
|
||||
|
||||
@Inject
|
||||
public TagToBootScript(@Provider URI endpoint, Json json, Map<String, Client> tagToClient,
|
||||
Map<String, List<String>> runListForTag, @Named("installChefGems") Statement installChefGems) {
|
||||
this.endpoint = checkNotNull(endpoint, "endpoint");
|
||||
this.json = checkNotNull(json, "json");
|
||||
this.tagToClient = checkNotNull(tagToClient, "tagToClient");
|
||||
this.runListForTag = checkNotNull(runListForTag, "runListForTag");
|
||||
this.installChefGems = checkNotNull(installChefGems, "installChefGems");
|
||||
}
|
||||
|
||||
public Payload apply(String tag) {
|
||||
checkNotNull(tag, "tag");
|
||||
|
||||
Client client = tagToClient.get(tag);
|
||||
checkState(client != null, "could not get a client for tag %s", tag);
|
||||
checkState(client.getClientname() != null, "clientname null for %s", client);
|
||||
checkState(client.getPrivateKey() != null, "privatekey null for %s", client);
|
||||
|
||||
List<String> runList = runListForTag.get(tag);
|
||||
checkState(runList != null, "runList for %s was not found", tag);
|
||||
checkState(runList.size() > 0, "runList for %s was empty", tag);
|
||||
|
||||
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\"", client.getClientname()), String.format(
|
||||
"chef_server_url \"%s\"", endpoint)));
|
||||
|
||||
Statement createValidationPem = createFile(chefConfigDir + "{fs}validation.pem", Splitter.on('\n').split(
|
||||
Pems.pem(client.getPrivateKey())));
|
||||
|
||||
String chefBootFile = chefConfigDir + "{fs}first-boot.json";
|
||||
|
||||
Statement createFirstBoot = createFile(chefBootFile, Collections.singleton(json.toJson(ImmutableMap
|
||||
.<String, List<String>> of("run_list", runList), RUN_LIST_TYPE)));
|
||||
|
||||
Statement runChef = exec("chef-client -j " + chefBootFile);
|
||||
|
||||
Statement bootstrapAndRunChef = newStatementList(installChefGems, createChefConfigDir, createClientRb,
|
||||
createValidationPem, createFirstBoot, runChef);
|
||||
|
||||
String runScript = bootstrapAndRunChef.render(OsFamily.UNIX);
|
||||
return newStringPayload(runScript);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,6 +21,7 @@ package org.jclouds.chef.internal;
|
|||
|
||||
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.chef.reference.ChefConstants.CHEF_BOOTSTRAP_DATABAG;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -38,6 +39,7 @@ public abstract class BaseChefPropertiesBuilder extends PropertiesBuilder {
|
|||
Properties properties = super.defaultProperties();
|
||||
properties.setProperty(PROPERTY_SESSION_INTERVAL, "1");
|
||||
properties.setProperty(PROPERTY_API_VERSION, ChefAsyncClient.VERSION);
|
||||
properties.setProperty(CHEF_BOOTSTRAP_DATABAG, "bootstrap");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
package org.jclouds.chef.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.jclouds.chef.reference.ChefConstants.CHEF_BOOTSTRAP_DATABAG;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
|
@ -34,7 +36,10 @@ import javax.inject.Singleton;
|
|||
import org.jclouds.chef.ChefContext;
|
||||
import org.jclouds.chef.ChefService;
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.jclouds.chef.domain.DatabagItem;
|
||||
import org.jclouds.chef.domain.Node;
|
||||
import org.jclouds.chef.functions.RunListForTag;
|
||||
import org.jclouds.chef.functions.TagToBootScript;
|
||||
import org.jclouds.chef.reference.ChefConstants;
|
||||
import org.jclouds.chef.strategy.CleanupStaleNodesAndClients;
|
||||
import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
|
||||
|
@ -43,12 +48,15 @@ import org.jclouds.chef.strategy.DeleteAllNodesInList;
|
|||
import org.jclouds.chef.strategy.ListClients;
|
||||
import org.jclouds.chef.strategy.ListNodes;
|
||||
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
|
||||
import org.jclouds.io.Payload;
|
||||
import org.jclouds.io.Payloads;
|
||||
import org.jclouds.io.payloads.RSADecryptingPayload;
|
||||
import org.jclouds.io.payloads.RSAEncryptingPayload;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
||||
|
@ -72,13 +80,17 @@ public class BaseChefService implements ChefService {
|
|||
private final ListClients listClients;
|
||||
private final UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode;
|
||||
private final Provider<PrivateKey> privateKey;
|
||||
private final TagToBootScript tagToBootScript;
|
||||
private final String databag;
|
||||
private final RunListForTag runListForTag;
|
||||
|
||||
@Inject
|
||||
protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients,
|
||||
CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes,
|
||||
DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes,
|
||||
DeleteAllClientsInList deleteAllClientsInList, ListClients listClients,
|
||||
UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, Provider<PrivateKey> privateKey) {
|
||||
UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, Provider<PrivateKey> privateKey,
|
||||
@Named(CHEF_BOOTSTRAP_DATABAG) String databag, TagToBootScript tagToBootScript, RunListForTag runListForTag) {
|
||||
this.chefContext = checkNotNull(chefContext, "chefContext");
|
||||
this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients");
|
||||
this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes,
|
||||
|
@ -90,6 +102,9 @@ public class BaseChefService implements ChefService {
|
|||
this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode,
|
||||
"updateAutomaticAttributesOnNode");
|
||||
this.privateKey = checkNotNull(privateKey, "privateKey");
|
||||
this.tagToBootScript = checkNotNull(tagToBootScript, "tagToBootScript");
|
||||
this.databag = checkNotNull(databag, "databag");
|
||||
this.runListForTag = checkNotNull(runListForTag, "runListForTag");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,6 +167,30 @@ public class BaseChefService implements ChefService {
|
|||
return chefContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Payload createClientAndBootstrapScriptForTag(String tag) {
|
||||
return tagToBootScript.apply(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRunListForTag(Iterable<String> runList, String tag) {
|
||||
try {
|
||||
chefContext.getApi().createDatabag(databag);
|
||||
} catch (IllegalStateException e) {
|
||||
|
||||
}
|
||||
chefContext.getApi().updateDatabagItem(
|
||||
databag,
|
||||
new DatabagItem(tag, chefContext.utils().json().toJson(
|
||||
ImmutableMap.<String, List<String>> of("run_list", Lists.newArrayList(runList)),
|
||||
RunListForTag.RUN_LIST_TYPE)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRunListForTag(String tag) {
|
||||
return runListForTag.apply(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
|
||||
return ByteStreams.toByteArray(new RSADecryptingPayload(Payloads.newPayload(supplier.getInput()), privateKey
|
||||
|
|
|
@ -28,8 +28,7 @@ public interface ChefConstants {
|
|||
/**
|
||||
* There are generally 3 types of identities
|
||||
* <ul>
|
||||
* <li>validator - used to create clients within an organization; {@code
|
||||
* orgname}-validator</li>
|
||||
* <li>validator - used to create clients within an organization; {@code orgname}-validator</li>
|
||||
* <li>client - scoped to an organization, used on nodes to run chef</li>
|
||||
* <li>user - used to run commands like knife and access cookbook sites</li>
|
||||
* </ul>
|
||||
|
@ -49,4 +48,11 @@ public interface ChefConstants {
|
|||
public static final String CHEF_NODE = "chef.node";
|
||||
public static final String CHEF_NODE_PATTERN = "chef.node-pattern";
|
||||
public static final String CHEF_RUN_LIST = "chef.run-list";
|
||||
/**
|
||||
* databag that holds chef bootstrap hints, should be a json ball in the following format:
|
||||
* <p/>
|
||||
* {"tag":{"run_list":["recipe[apache2]"]}}
|
||||
*/
|
||||
public static final String CHEF_BOOTSTRAP_DATABAG = "chef.bootstrap-databag";
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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 org.jclouds.chef.statements;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
import org.jclouds.util.Utils;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class InstallChefGems implements Statement {
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
|
@ -18,16 +18,25 @@
|
|||
*/
|
||||
package org.jclouds.chef.test.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.blobstore.TransientAsyncBlobStore;
|
||||
import org.jclouds.chef.ChefAsyncClient;
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.config.BaseChefRestClientModule;
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.jclouds.chef.functions.ClientForTag;
|
||||
import org.jclouds.chef.functions.RunListForTag;
|
||||
import org.jclouds.chef.statements.InstallChefGems;
|
||||
import org.jclouds.chef.test.TransientChefAsyncClient;
|
||||
import org.jclouds.chef.test.TransientChefClient;
|
||||
import org.jclouds.rest.RestContextFactory;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
|
@ -44,8 +53,9 @@ public class TransientChefClientModule extends BaseChefRestClientModule<Transien
|
|||
@Override
|
||||
protected void configure() {
|
||||
bind(TransientAsyncBlobStore.class).annotatedWith(Names.named("databags")).toInstance(
|
||||
new RestContextFactory().createContextBuilder("transient", "foo", "bar").buildInjector().getInstance(
|
||||
TransientAsyncBlobStore.class));
|
||||
new RestContextFactory().createContextBuilder("transient", "foo", "bar").buildInjector().getInstance(
|
||||
TransientAsyncBlobStore.class));
|
||||
bind(Statement.class).annotatedWith(Names.named("installChefGems")).to(InstallChefGems.class);
|
||||
super.configure();
|
||||
}
|
||||
|
||||
|
@ -60,4 +70,16 @@ public class TransientChefClientModule extends BaseChefRestClientModule<Transien
|
|||
return in;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Map<String, List<String>> runListForTag(RunListForTag runListForTag) {
|
||||
return new MapMaker().makeComputingMap(runListForTag);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Map<String, Client> tagToClient(ClientForTag tagToClient) {
|
||||
return new MapMaker().makeComputingMap(tagToClient);
|
||||
}
|
||||
|
||||
}
|
|
@ -67,3 +67,6 @@
|
|||
(is (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"}))
|
||||
(is (= {:id "databag-item2" :value "databag-value2"} (databag-item "databag" "databag-item2"))))
|
||||
|
||||
(deftest run-list-test
|
||||
(update-run-list #{"recipe[foo]"} "tag")
|
||||
(is (= ["recipe[foo]"] (run-list "tag"))))
|
||||
|
|
|
@ -39,7 +39,7 @@ import com.google.inject.Injector;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "chef.BindHexEncodedMD5sToJsonPayloadTest")
|
||||
@Test(groups = "unit", testName = "chef.BootstrapChefClientTest")
|
||||
public class BindHexEncodedMD5sToJsonPayloadTest {
|
||||
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule());
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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 org.jclouds.chef.functions;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "chef.ClientForTagTest")
|
||||
public class ClientForTagTest {
|
||||
|
||||
public void testWhenNoClientsInList() throws IOException {
|
||||
ChefClient chefClient = createMock(ChefClient.class);
|
||||
Client client = createMock(Client.class);
|
||||
PrivateKey privateKey = createMock(PrivateKey.class);
|
||||
|
||||
ClientForTag fn = new ClientForTag(chefClient);
|
||||
|
||||
expect(chefClient.listClients()).andReturn(ImmutableSet.<String> of());
|
||||
expect(chefClient.createClient("foo-validator-00")).andReturn(client);
|
||||
expect(client.getPrivateKey()).andReturn(privateKey);
|
||||
|
||||
replay(client);
|
||||
replay(chefClient);
|
||||
|
||||
Client compare = fn.apply("foo");
|
||||
assertEquals(compare.getClientname(), "foo-validator-00");
|
||||
assertEquals(compare.getName(), "foo-validator-00");
|
||||
assertEquals(compare.getPrivateKey(), privateKey);
|
||||
|
||||
verify(client);
|
||||
verify(chefClient);
|
||||
}
|
||||
|
||||
public void testWhenClientsInListAddsToEnd() throws IOException {
|
||||
ChefClient chefClient = createMock(ChefClient.class);
|
||||
Client client = createMock(Client.class);
|
||||
PrivateKey privateKey = createMock(PrivateKey.class);
|
||||
|
||||
ClientForTag fn = new ClientForTag(chefClient);
|
||||
|
||||
expect(chefClient.listClients()).andReturn(
|
||||
ImmutableSet.<String> of("foo-validator-00", "foo-validator-01", "foo-validator-02"));
|
||||
expect(chefClient.createClient("foo-validator-03")).andReturn(client);
|
||||
expect(client.getPrivateKey()).andReturn(privateKey);
|
||||
|
||||
replay(client);
|
||||
replay(chefClient);
|
||||
|
||||
Client compare = fn.apply("foo");
|
||||
assertEquals(compare.getClientname(), "foo-validator-03");
|
||||
assertEquals(compare.getName(), "foo-validator-03");
|
||||
assertEquals(compare.getPrivateKey(), privateKey);
|
||||
|
||||
verify(client);
|
||||
verify(chefClient);
|
||||
}
|
||||
|
||||
public void testWhenClientsInListReplacesMissing() throws IOException {
|
||||
ChefClient chefClient = createMock(ChefClient.class);
|
||||
Client client = createMock(Client.class);
|
||||
PrivateKey privateKey = createMock(PrivateKey.class);
|
||||
|
||||
ClientForTag fn = new ClientForTag(chefClient);
|
||||
|
||||
expect(chefClient.listClients()).andReturn(ImmutableSet.<String> of("foo-validator-00", "foo-validator-02"));
|
||||
expect(chefClient.createClient("foo-validator-01")).andReturn(client);
|
||||
expect(client.getPrivateKey()).andReturn(privateKey);
|
||||
|
||||
replay(client);
|
||||
replay(chefClient);
|
||||
|
||||
Client compare = fn.apply("foo");
|
||||
assertEquals(compare.getClientname(), "foo-validator-01");
|
||||
assertEquals(compare.getName(), "foo-validator-01");
|
||||
assertEquals(compare.getPrivateKey(), privateKey);
|
||||
|
||||
verify(client);
|
||||
verify(chefClient);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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 org.jclouds.chef.functions;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jclouds.chef.ChefClient;
|
||||
import org.jclouds.chef.config.ChefParserModule;
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.jclouds.chef.domain.DatabagItem;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "chef.RunListForTagTest")
|
||||
public class RunListForTagTest {
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule());
|
||||
Json json = injector.getInstance(Json.class);
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testWhenNoDatabagItem() throws IOException {
|
||||
ChefClient chefClient = createMock(ChefClient.class);
|
||||
Client client = createMock(Client.class);
|
||||
|
||||
RunListForTag fn = new RunListForTag("jclouds", chefClient, json);
|
||||
|
||||
expect(chefClient.getDatabagItem("jclouds", "foo")).andReturn(null);
|
||||
|
||||
replay(client);
|
||||
replay(chefClient);
|
||||
|
||||
fn.apply("foo");
|
||||
|
||||
verify(client);
|
||||
verify(chefClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneRecipe() throws IOException {
|
||||
ChefClient chefClient = createMock(ChefClient.class);
|
||||
Client client = createMock(Client.class);
|
||||
|
||||
RunListForTag fn = new RunListForTag("jclouds", chefClient, json);
|
||||
|
||||
expect(chefClient.getDatabagItem("jclouds", "foo")).andReturn(
|
||||
new DatabagItem("foo", "{\"run_list\":[\"recipe[apache2]\"]}"));
|
||||
|
||||
replay(client);
|
||||
replay(chefClient);
|
||||
|
||||
assertEquals(fn.apply("foo"), ImmutableList.of("recipe[apache2]"));
|
||||
|
||||
verify(client);
|
||||
verify(chefClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoRecipes() throws IOException {
|
||||
ChefClient chefClient = createMock(ChefClient.class);
|
||||
Client client = createMock(Client.class);
|
||||
|
||||
RunListForTag fn = new RunListForTag("jclouds", chefClient, json);
|
||||
|
||||
expect(chefClient.getDatabagItem("jclouds", "foo")).andReturn(
|
||||
new DatabagItem("foo", "{\"run_list\":[\"recipe[apache2]\",\"recipe[mysql]\"]}"));
|
||||
|
||||
replay(client);
|
||||
replay(chefClient);
|
||||
|
||||
assertEquals(fn.apply("foo"), ImmutableList.of("recipe[apache2]", "recipe[mysql]"));
|
||||
|
||||
verify(client);
|
||||
verify(chefClient);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* 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 org.jclouds.chef.functions;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.chef.config.ChefParserModule;
|
||||
import org.jclouds.chef.domain.Client;
|
||||
import org.jclouds.chef.statements.InstallChefGems;
|
||||
import org.jclouds.crypto.PemsTest;
|
||||
import org.jclouds.json.Json;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.io.Resources;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "chef.TagToBootScriptTest")
|
||||
public class TagToBootScriptTest {
|
||||
|
||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule());
|
||||
Json json = injector.getInstance(Json.class);
|
||||
Statement installChefGems = new InstallChefGems();
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMustHaveClients() {
|
||||
TagToBootScript fn = new TagToBootScript(URI.create("http://localhost:4000"), json, ImmutableMap
|
||||
.<String, Client> of(), ImmutableMap.<String, List<String>> of("foo", ImmutableList
|
||||
.of("recipe[apache2]")), installChefGems);
|
||||
fn.apply("foo");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMustHaveRunScripts() {
|
||||
TagToBootScript fn = new TagToBootScript(URI.create("http://localhost:4000"), json, ImmutableMap
|
||||
.<String, Client> of("foo", createMock(Client.class)), ImmutableMap.<String, List<String>> of(), installChefGems);
|
||||
fn.apply("foo");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMustHaveRunScriptsValue() {
|
||||
TagToBootScript fn = new TagToBootScript(URI.create("http://localhost:4000"), json, ImmutableMap
|
||||
.<String, Client> of("foo", createMock(Client.class)), ImmutableMap.<String, List<String>> of("foo",
|
||||
ImmutableList.<String> of()), installChefGems);
|
||||
fn.apply("foo");
|
||||
}
|
||||
|
||||
public void testOneRecipe() throws IOException {
|
||||
Client client = createMock(Client.class);
|
||||
PrivateKey privateKey = createMock(PrivateKey.class);
|
||||
|
||||
TagToBootScript fn = new TagToBootScript(URI.create("http://localhost:4000"), json, ImmutableMap
|
||||
.<String, Client> of("foo", client), ImmutableMap.<String, List<String>> of("foo", ImmutableList
|
||||
.<String> of("recipe[apache2]")), installChefGems);
|
||||
|
||||
expect(client.getClientname()).andReturn("fooclient").atLeastOnce();
|
||||
expect(client.getPrivateKey()).andReturn(privateKey).atLeastOnce();
|
||||
expect(privateKey.getEncoded()).andReturn(PemsTest.PRIVATE_KEY.getBytes());
|
||||
|
||||
replay(client);
|
||||
replay(privateKey);
|
||||
|
||||
assertEquals(fn.apply("foo").getRawContent(), CharStreams.toString(Resources.newReaderSupplier(Resources
|
||||
.getResource("one-recipe.sh"), Charsets.UTF_8)));
|
||||
|
||||
verify(client);
|
||||
verify(privateKey);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
if [ ! -f /usr/bin/chef-client ]; then
|
||||
apt-get update
|
||||
apt-get install -y ruby ruby1.8-dev build-essential wget libruby-extras libruby1.8-extras
|
||||
mkdir -p /tmp/bootchef
|
||||
(
|
||||
cd /tmp/bootchef
|
||||
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
|
||||
ruby setup.rb
|
||||
cp /usr/bin/gem1.8 /usr/bin/gem
|
||||
)
|
||||
rm -rf /tmp/bootchef
|
||||
gem install chef ohai --no-rdoc --no-ri --verbose
|
||||
fi
|
||||
mkdir -p /etc/chef
|
||||
cat > /etc/chef/client.rb <<'END_OF_FILE'
|
||||
require 'rubygems'
|
||||
require 'ohai'
|
||||
o = Ohai::System.new
|
||||
o.all_plugins
|
||||
node_name "foo-" + o[:ipaddress]
|
||||
log_level :info
|
||||
log_location STDOUT
|
||||
validation_client_name "fooclient"
|
||||
chef_server_url "http://localhost:4000"
|
||||
END_OF_FILE
|
||||
cat > /etc/chef/validation.pem <<'END_OF_FILE'
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVB
|
||||
eWIyWkpKcUdtMEtLUis4bmZRSk5zU2QrRjl0WE5NVjdDZk9jVzZqc3FzOEVaZ2lW
|
||||
ClIwOWhEMUlZT2o0WXFNMHFKT05sZ3lnNHhSV2V3ZFNHN1FUUGoxbEpwVkFpZGE5
|
||||
c1h5MitrenlhZ1pBMUFtME8KWmNicWI1aG9lSURnY1grZURhNzlzMHUwRG9tamNm
|
||||
TzlFS2h2SExCeit6TSszUXFQUmtQVjhuWVRiZnMrSGpWegp6T1U2RDFCMFhSMytJ
|
||||
UFpabDJBbldzMmQwcWhuU3RIY0RVdm5SVlEwUDQ4Mll3TjlWZ2NlT1p0cFB6MERD
|
||||
S0VKCjVUeDVTVHViOGswL3p0L1ZBTUhRYWZMU3VRTUxkMnM0Wkx1T1pwdE4vL3VB
|
||||
c1RteGlyZXFkMzd6KzhaVGRCYkoKOExFcEoraUNYdVNmbTVhVWg3aXc2b3h2VG9Z
|
||||
MkFMNTMraksyVVFJREFRQUJBb0lCQVFEQTg4QjNpL3hXbjB2WApCVnhGYW1DWW9l
|
||||
Y3VOakd3WFhrU3laZXc2MTZBK0VPQ3U0N2JoNGFUdXJkRmJZTDBZRmFBdGFXdnps
|
||||
YU4yZUhnCkRiK0hEdVRlZkUyOStXa2NHazZTc2hQbWl6NVQwWE9DQUlDV3c2d1NW
|
||||
RGtIbUd3UzRqWnZiQUZtN1c4bndHazkKWWh4Z3hGaVJuZ3N3SlpGb3BPTG9GNVdY
|
||||
czJ0ZDhndUlZTnNsTXBvN3R1NTBpRm5CSHdLTzJac1BBazh0OW5uUwp4bERhdkty
|
||||
dXltRW1xSENyMytkdGlvNWVhZW5KY3AzZmpvWEJRT0tVazNpcElJMjlYUkI4TnFl
|
||||
Q1ZWLzdLeHdxCmNrcU9CRWJSd0JjbGNreUliRCtSaUFnS3ZPZWxPUmpFaUU5UjQy
|
||||
dnVxdnhSQTZrOWtkOW83dXRsWDBBVXRwRW4KM2daYzZMZXBBb0dCQVA5YWVsNVk3
|
||||
NStzSzJKSlVOT09oTzhhZTQ1Y2RzaWxwMnlJMFgrVUJhU3VRczIrZHlQcAprcEVI
|
||||
QXhkNHBtbVN2bi84YzlUbEVaaHIrcVliQUJYVlBsRG5jeHBJdXcyQWpiazdzL1M0
|
||||
WGFTS3NScXBYTDU3CnpqL1FPcUxrUms4K09WVjlxNmxNZVFOcUx0RWoxdTZKUHZp
|
||||
WDcwUm8rRlF0UnR0Tk9ZYmZkUC9mQW9HQkFNcEEKWGpSNXdvVjVzVWIrUkVnOXZF
|
||||
dVlvOFJTeU9hcnhxS0ZDSVhWVU5zTE94KzIyK0FLNCtDUXBidWVXTjdqb3RybApZ
|
||||
RDZ1VDZzdldpM0FBQzdraVkwVUkvZmpWUFJDVWk4dFZvUVVFMFRhVTVWTElUYVlP
|
||||
QitXL2JCYURFNE05NTYwCjFOdURXTzkwYmFBNWRmVTQ0aXV6dmEwMnJHSlhLOStu
|
||||
UzNvOG5rL1BBb0dCQUxPTDZkam5EZTRtd0FhRzZKY28KY2Q0eHI4amt5UHpDUlp1
|
||||
eUJDU0Jid3BoSVVYTGM3aERwclBreTA2NG5jSkQxVURtd0lka1hkL2ZwTWtnMlFt
|
||||
QQovQ1VrNkxFRmpNaXNxSG9qT2FDTDlnUVpKUGhMTjVRVU4yeDFQSldHanMxdlFo
|
||||
OFRreDBpVVVDT2E4YlFQWE5SCiszNE9Uc1c2VFVuYTRDU1pBeWNMZmhmZkFvR0JB
|
||||
SWdnVnNlZkJDdnVRa0YwTmVVaG1EQ1JaZmhuZDh5NTVSSFIKMUhDdnFLSWxwdity
|
||||
aGNYL3pteUJMdXRlb3BZeVJKUnNPaUUyRlcwMGk4K3JJUFJ1NFozUTVueWJ4N3cz
|
||||
UHpWOQpvSE41UjViYUU5T3lJNEtwWld6dHBZWWl0WkY2N05jbkF2VlVMSEhPdlZK
|
||||
UUduS1lmTEhKWW1ySkY3R0Exb2pNCkF1TWRGYmpGQW9HQVB4VWh4d0Z5OGdhcUJh
|
||||
aEtVRVpuNEY4MUhGUDVpaEdoa1Q0UUw2QUZQTzJlK0poSUdqdVIKMjcrODVoY0Zx
|
||||
UStISFZ0RnNtODFiL2ErUjdQNFV1Q1JnYzhlQ2p4UU1vSjFYbDRuN1ZialBiSE1u
|
||||
SU4wUnl2ZApPNFpwV0RXWW5DTzAyMUpUT1VVT0o0Si95MDQxNkJ2a3cwejU5eTdz
|
||||
Tlg3d0RCQkhIYksvWENjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
-----END PRIVATE KEY-----
|
||||
END_OF_FILE
|
||||
cat > /etc/chef/first-boot.json <<'END_OF_FILE'
|
||||
{"run_list":["recipe[apache2]"]}
|
||||
END_OF_FILE
|
||||
chef-client -j /etc/chef/first-boot.json
|
|
@ -267,7 +267,7 @@ public class Pems {
|
|||
* @throws IOException
|
||||
* @throws CertificateEncodingException
|
||||
*/
|
||||
public static String pem(X509Certificate cert) throws IOException, CertificateEncodingException {
|
||||
public static String pem(X509Certificate cert) throws CertificateEncodingException {
|
||||
String marker = CERTIFICATE_X509_MARKER;
|
||||
return pem(cert.getEncoded(), marker);
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ public class Pems {
|
|||
* @throws IOException
|
||||
* @throws CertificateEncodingException
|
||||
*/
|
||||
public static String pem(PublicKey key) throws IOException {
|
||||
public static String pem(PublicKey key) {
|
||||
String marker = key instanceof RSAPublicKey ? PUBLIC_PKCS1_MARKER : PUBLIC_X509_MARKER;
|
||||
return pem(key.getEncoded(), marker);
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ public class Pems {
|
|||
* @throws IOException
|
||||
* @throws CertificateEncodingException
|
||||
*/
|
||||
public static String pem(PrivateKey key) throws IOException {
|
||||
public static String pem(PrivateKey key) {
|
||||
String marker = key instanceof RSAPrivateCrtKey ? PRIVATE_PKCS1_MARKER : PRIVATE_PKCS8_MARKER;
|
||||
return pem(key instanceof RSAPrivateCrtKey ? getEncoded(RSAPrivateCrtKey.class.cast(key)) : key.getEncoded(),
|
||||
marker);
|
||||
|
@ -320,7 +320,7 @@ public class Pems {
|
|||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
private static String pem(byte[] key, String marker) throws IOException {
|
||||
private static String pem(byte[] key, String marker) {
|
||||
return new StringBuilder(marker + "\n").append(
|
||||
Joiner.on('\n').join(Splitter.fixedLength(64).split(CryptoStreams.base64(key)))).append(
|
||||
"\n" + marker.replace("BEGIN", "END") + "\n").toString().trim();
|
||||
|
|
Loading…
Reference in New Issue