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;
|
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 org.testng.Assert.assertEquals;
|
||||||
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.FileNotFoundException;
|
||||||
|
@ -32,25 +28,18 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
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 org.jclouds.chef.ChefContext;
|
import org.jclouds.chef.ChefContext;
|
||||||
import org.jclouds.chef.ChefContextFactory;
|
import org.jclouds.chef.ChefContextFactory;
|
||||||
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.RunNodesException;
|
||||||
import org.jclouds.compute.domain.NodeMetadata;
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
import org.jclouds.compute.options.TemplateOptions;
|
import org.jclouds.compute.options.TemplateOptions;
|
||||||
import org.jclouds.compute.predicates.NodePredicates;
|
import org.jclouds.compute.predicates.NodePredicates;
|
||||||
import org.jclouds.crypto.Pems;
|
import org.jclouds.io.Payload;
|
||||||
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.ssh.jsch.config.JschSshClientModule;
|
||||||
import org.jclouds.util.Utils;
|
import org.jclouds.util.Utils;
|
||||||
import org.testng.annotations.AfterGroups;
|
import org.testng.annotations.AfterGroups;
|
||||||
|
@ -58,15 +47,10 @@ 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.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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -80,7 +64,6 @@ public class ChefComputeServiceLiveTest {
|
||||||
private String tag;
|
private String tag;
|
||||||
private String clientName;
|
private String clientName;
|
||||||
private String chefEndpoint;
|
private String chefEndpoint;
|
||||||
private Map<String, String> keyPair;
|
|
||||||
private Iterable<? extends NodeMetadata> nodes;
|
private Iterable<? extends NodeMetadata> nodes;
|
||||||
|
|
||||||
@BeforeGroups(groups = { "live" })
|
@BeforeGroups(groups = { "live" })
|
||||||
|
@ -97,7 +80,6 @@ public class ChefComputeServiceLiveTest {
|
||||||
"jclouds.compute.credential");
|
"jclouds.compute.credential");
|
||||||
computeContext = new ComputeServiceContextFactory().createContext(computeProvider, computeIdentity,
|
computeContext = new ComputeServiceContextFactory().createContext(computeProvider, computeIdentity,
|
||||||
computeCredential, ImmutableSet.of(new Log4JLoggingModule(), getSshModule()), props);
|
computeCredential, ImmutableSet.of(new Log4JLoggingModule(), getSshModule()), props);
|
||||||
keyPair = BaseComputeServiceLiveTest.setupKeyPair();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeGroups(groups = { "live" })
|
@BeforeGroups(groups = { "live" })
|
||||||
|
@ -113,69 +95,21 @@ 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() {
|
protected Module getSshModule() {
|
||||||
return new JschSshClientModule();
|
return new JschSshClientModule();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws IOException, InterruptedException {
|
public void testCanUpdateRunList() throws IOException {
|
||||||
clientName = findNextClientName(chefContext, tag + "-validator-%d");
|
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]");
|
Payload bootstrap = chefContext.getChefService().createClientAndBootstrapScriptForTag(tag);
|
||||||
Json json = computeContext.utils().json();
|
TemplateOptions options = computeContext.getComputeService().templateOptions().runScript(bootstrap);
|
||||||
|
|
||||||
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 {
|
try {
|
||||||
nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, options);
|
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" })
|
@AfterGroups(groups = { "live" })
|
||||||
public void teardownCompute() {
|
public void teardownCompute() {
|
||||||
if (computeContext != null) {
|
if (computeContext != null) {
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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
|
Licensed to the Apache Software Foundation (ASF) under one or
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
more contributor license agreements. See the NOTICE file
|
||||||
this work for additional information regarding copyright ownership.
|
distributed with this work for additional information regarding
|
||||||
The ASF licenses this file to you under the Apache License, Version
|
copyright ownership. The ASF licenses this file to you under the
|
||||||
2.0 (the "License"); you may not use this file except in compliance
|
Apache License, Version 2.0 (the "License"); you may not use
|
||||||
with the License. You may obtain a copy of the License at
|
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
|
http://www.apache.org/licenses/LICENSE-2.0.html Unless required
|
||||||
applicable law or agreed to in writing, software distributed under the
|
by applicable law or agreed to in writing, software distributed
|
||||||
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
CONDITIONS OF ANY KIND, either express or implied. See the License for
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
the specific language governing permissions and limitations under the
|
See the License for the specific language governing permissions
|
||||||
License.
|
and limitations under the License.
|
||||||
====================================================================
|
====================================================================
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
@ -71,6 +73,17 @@
|
||||||
<artifactId>jclouds-core</artifactId>
|
<artifactId>jclouds-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</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>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>jclouds-core</artifactId>
|
<artifactId>jclouds-core</artifactId>
|
||||||
|
|
|
@ -131,6 +131,24 @@ unit testing"
|
||||||
([#^ChefService chef]
|
([#^ChefService chef]
|
||||||
(seq (.listNodesDetails 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
|
(defn databags
|
||||||
"Retrieve the names of the existing data bags in your chef server."
|
"Retrieve the names of the existing data bags in your chef server."
|
||||||
([] (databags *chef*))
|
([] (databags *chef*))
|
||||||
|
|
|
@ -21,10 +21,12 @@ package org.jclouds.chef;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.jclouds.chef.domain.Client;
|
import org.jclouds.chef.domain.Client;
|
||||||
import org.jclouds.chef.domain.Node;
|
import org.jclouds.chef.domain.Node;
|
||||||
import org.jclouds.chef.internal.BaseChefService;
|
import org.jclouds.chef.internal.BaseChefService;
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.io.InputSupplier;
|
import com.google.common.io.InputSupplier;
|
||||||
|
@ -56,6 +58,43 @@ public interface ChefService {
|
||||||
*/
|
*/
|
||||||
Node createNodeAndPopulateAutomaticAttributes(String nodeName, Iterable<String> runList);
|
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);
|
void deleteAllNodesInList(Iterable<String> names);
|
||||||
|
|
||||||
Iterable<? extends Node> listNodesDetails();
|
Iterable<? extends Node> listNodesDetails();
|
||||||
|
|
|
@ -19,10 +19,24 @@
|
||||||
|
|
||||||
package org.jclouds.chef.config;
|
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.ChefAsyncClient;
|
||||||
import org.jclouds.chef.ChefClient;
|
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.http.RequiresHttp;
|
||||||
import org.jclouds.rest.ConfiguresRestClient;
|
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.
|
* Configures the Chef connection.
|
||||||
|
@ -37,4 +51,22 @@ public class ChefRestClientModule extends BaseChefRestClientModule<ChefClient, C
|
||||||
super(ChefClient.class, ChefAsyncClient.class);
|
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_API_VERSION;
|
||||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||||
|
import static org.jclouds.chef.reference.ChefConstants.CHEF_BOOTSTRAP_DATABAG;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ public abstract class BaseChefPropertiesBuilder extends PropertiesBuilder {
|
||||||
Properties properties = super.defaultProperties();
|
Properties properties = super.defaultProperties();
|
||||||
properties.setProperty(PROPERTY_SESSION_INTERVAL, "1");
|
properties.setProperty(PROPERTY_SESSION_INTERVAL, "1");
|
||||||
properties.setProperty(PROPERTY_API_VERSION, ChefAsyncClient.VERSION);
|
properties.setProperty(PROPERTY_API_VERSION, ChefAsyncClient.VERSION);
|
||||||
|
properties.setProperty(CHEF_BOOTSTRAP_DATABAG, "bootstrap");
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,12 @@
|
||||||
package org.jclouds.chef.internal;
|
package org.jclouds.chef.internal;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
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.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -34,7 +36,10 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.chef.ChefContext;
|
import org.jclouds.chef.ChefContext;
|
||||||
import org.jclouds.chef.ChefService;
|
import org.jclouds.chef.ChefService;
|
||||||
import org.jclouds.chef.domain.Client;
|
import org.jclouds.chef.domain.Client;
|
||||||
|
import org.jclouds.chef.domain.DatabagItem;
|
||||||
import org.jclouds.chef.domain.Node;
|
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.reference.ChefConstants;
|
||||||
import org.jclouds.chef.strategy.CleanupStaleNodesAndClients;
|
import org.jclouds.chef.strategy.CleanupStaleNodesAndClients;
|
||||||
import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
|
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.ListClients;
|
||||||
import org.jclouds.chef.strategy.ListNodes;
|
import org.jclouds.chef.strategy.ListNodes;
|
||||||
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
|
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
import org.jclouds.io.Payloads;
|
import org.jclouds.io.Payloads;
|
||||||
import org.jclouds.io.payloads.RSADecryptingPayload;
|
import org.jclouds.io.payloads.RSADecryptingPayload;
|
||||||
import org.jclouds.io.payloads.RSAEncryptingPayload;
|
import org.jclouds.io.payloads.RSAEncryptingPayload;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
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.ByteStreams;
|
||||||
import com.google.common.io.InputSupplier;
|
import com.google.common.io.InputSupplier;
|
||||||
|
|
||||||
|
@ -72,13 +80,17 @@ public class BaseChefService implements ChefService {
|
||||||
private final ListClients listClients;
|
private final ListClients listClients;
|
||||||
private final UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode;
|
private final UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode;
|
||||||
private final Provider<PrivateKey> privateKey;
|
private final Provider<PrivateKey> privateKey;
|
||||||
|
private final TagToBootScript tagToBootScript;
|
||||||
|
private final String databag;
|
||||||
|
private final RunListForTag runListForTag;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients,
|
protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients,
|
||||||
CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes,
|
CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes,
|
||||||
DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes,
|
DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes,
|
||||||
DeleteAllClientsInList deleteAllClientsInList, ListClients listClients,
|
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.chefContext = checkNotNull(chefContext, "chefContext");
|
||||||
this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients");
|
this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients");
|
||||||
this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes,
|
this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes,
|
||||||
|
@ -90,6 +102,9 @@ public class BaseChefService implements ChefService {
|
||||||
this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode,
|
this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode,
|
||||||
"updateAutomaticAttributesOnNode");
|
"updateAutomaticAttributesOnNode");
|
||||||
this.privateKey = checkNotNull(privateKey, "privateKey");
|
this.privateKey = checkNotNull(privateKey, "privateKey");
|
||||||
|
this.tagToBootScript = checkNotNull(tagToBootScript, "tagToBootScript");
|
||||||
|
this.databag = checkNotNull(databag, "databag");
|
||||||
|
this.runListForTag = checkNotNull(runListForTag, "runListForTag");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,6 +167,30 @@ public class BaseChefService implements ChefService {
|
||||||
return chefContext;
|
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
|
@Override
|
||||||
public byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
|
public byte[] decrypt(InputSupplier<? extends InputStream> supplier) throws IOException {
|
||||||
return ByteStreams.toByteArray(new RSADecryptingPayload(Payloads.newPayload(supplier.getInput()), privateKey
|
return ByteStreams.toByteArray(new RSADecryptingPayload(Payloads.newPayload(supplier.getInput()), privateKey
|
||||||
|
|
|
@ -28,8 +28,7 @@ public interface ChefConstants {
|
||||||
/**
|
/**
|
||||||
* There are generally 3 types of identities
|
* There are generally 3 types of identities
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>validator - used to create clients within an organization; {@code
|
* <li>validator - used to create clients within an organization; {@code orgname}-validator</li>
|
||||||
* orgname}-validator</li>
|
|
||||||
* <li>client - scoped to an organization, used on nodes to run chef</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>
|
* <li>user - used to run commands like knife and access cookbook sites</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
@ -49,4 +48,11 @@ public interface ChefConstants {
|
||||||
public static final String CHEF_NODE = "chef.node";
|
public static final String CHEF_NODE = "chef.node";
|
||||||
public static final String CHEF_NODE_PATTERN = "chef.node-pattern";
|
public static final String CHEF_NODE_PATTERN = "chef.node-pattern";
|
||||||
public static final String CHEF_RUN_LIST = "chef.run-list";
|
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;
|
package org.jclouds.chef.test.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.blobstore.TransientAsyncBlobStore;
|
import org.jclouds.blobstore.TransientAsyncBlobStore;
|
||||||
import org.jclouds.chef.ChefAsyncClient;
|
import org.jclouds.chef.ChefAsyncClient;
|
||||||
import org.jclouds.chef.ChefClient;
|
import org.jclouds.chef.ChefClient;
|
||||||
import org.jclouds.chef.config.BaseChefRestClientModule;
|
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.TransientChefAsyncClient;
|
||||||
import org.jclouds.chef.test.TransientChefClient;
|
import org.jclouds.chef.test.TransientChefClient;
|
||||||
import org.jclouds.rest.RestContextFactory;
|
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.Provides;
|
||||||
import com.google.inject.name.Names;
|
import com.google.inject.name.Names;
|
||||||
|
|
||||||
|
@ -46,6 +55,7 @@ public class TransientChefClientModule extends BaseChefRestClientModule<Transien
|
||||||
bind(TransientAsyncBlobStore.class).annotatedWith(Names.named("databags")).toInstance(
|
bind(TransientAsyncBlobStore.class).annotatedWith(Names.named("databags")).toInstance(
|
||||||
new RestContextFactory().createContextBuilder("transient", "foo", "bar").buildInjector().getInstance(
|
new RestContextFactory().createContextBuilder("transient", "foo", "bar").buildInjector().getInstance(
|
||||||
TransientAsyncBlobStore.class));
|
TransientAsyncBlobStore.class));
|
||||||
|
bind(Statement.class).annotatedWith(Names.named("installChefGems")).to(InstallChefGems.class);
|
||||||
super.configure();
|
super.configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,4 +70,16 @@ public class TransientChefClientModule extends BaseChefRestClientModule<Transien
|
||||||
return in;
|
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 (create-databag-item "databag" {:id "databag-item2" :value "databag-value2"}))
|
||||||
(is (= {:id "databag-item2" :value "databag-value2"} (databag-item "databag" "databag-item2"))))
|
(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
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
@Test(groups = "unit", testName = "chef.BindHexEncodedMD5sToJsonPayloadTest")
|
@Test(groups = "unit", testName = "chef.BootstrapChefClientTest")
|
||||||
public class BindHexEncodedMD5sToJsonPayloadTest {
|
public class BindHexEncodedMD5sToJsonPayloadTest {
|
||||||
|
|
||||||
Injector injector = Guice.createInjector(new ChefParserModule(), new GsonModule());
|
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 IOException
|
||||||
* @throws CertificateEncodingException
|
* @throws CertificateEncodingException
|
||||||
*/
|
*/
|
||||||
public static String pem(X509Certificate cert) throws IOException, CertificateEncodingException {
|
public static String pem(X509Certificate cert) throws CertificateEncodingException {
|
||||||
String marker = CERTIFICATE_X509_MARKER;
|
String marker = CERTIFICATE_X509_MARKER;
|
||||||
return pem(cert.getEncoded(), marker);
|
return pem(cert.getEncoded(), marker);
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ public class Pems {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws CertificateEncodingException
|
* @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;
|
String marker = key instanceof RSAPublicKey ? PUBLIC_PKCS1_MARKER : PUBLIC_X509_MARKER;
|
||||||
return pem(key.getEncoded(), marker);
|
return pem(key.getEncoded(), marker);
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ public class Pems {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws CertificateEncodingException
|
* @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;
|
String marker = key instanceof RSAPrivateCrtKey ? PRIVATE_PKCS1_MARKER : PRIVATE_PKCS8_MARKER;
|
||||||
return pem(key instanceof RSAPrivateCrtKey ? getEncoded(RSAPrivateCrtKey.class.cast(key)) : key.getEncoded(),
|
return pem(key instanceof RSAPrivateCrtKey ? getEncoded(RSAPrivateCrtKey.class.cast(key)) : key.getEncoded(),
|
||||||
marker);
|
marker);
|
||||||
|
@ -320,7 +320,7 @@ public class Pems {
|
||||||
return bOut.toByteArray();
|
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(
|
return new StringBuilder(marker + "\n").append(
|
||||||
Joiner.on('\n').join(Splitter.fixedLength(64).split(CryptoStreams.base64(key)))).append(
|
Joiner.on('\n').join(Splitter.fixedLength(64).split(CryptoStreams.base64(key)))).append(
|
||||||
"\n" + marker.replace("BEGIN", "END") + "\n").toString().trim();
|
"\n" + marker.replace("BEGIN", "END") + "\n").toString().trim();
|
||||||
|
|
Loading…
Reference in New Issue