mirror of https://github.com/apache/jclouds.git
JCLOUDS-3: Bootstrap nodes in a custom environment
Added the environment where the nodes in a group must be created in the bootstrap data bag. This way the configuration is persisted and can be used between runs, such as the node run list. To accomodate the new bootstrap parameter, the method in the ChefService used to create the data bag has been refactored and a the new BootstrapConfig object has been created. This way, we'll be able to extend the information in the bootstrap databag in the future without changing the ChefService interface.
This commit is contained in:
parent
6ab817766a
commit
66dd885280
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jclouds.chef.domain.BootstrapConfig;
|
||||||
import org.jclouds.chef.domain.Client;
|
import org.jclouds.chef.domain.Client;
|
||||||
import org.jclouds.chef.domain.CookbookVersion;
|
import org.jclouds.chef.domain.CookbookVersion;
|
||||||
import org.jclouds.chef.domain.Environment;
|
import org.jclouds.chef.domain.Environment;
|
||||||
|
@ -74,22 +75,15 @@ public interface ChefService {
|
||||||
Statement createBootstrapScriptForGroup(String group);
|
Statement createBootstrapScriptForGroup(String group);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* assigns a run list to all nodes bootstrapped with a certain group
|
* Configures how the nodes of a certain group will be bootstrapped
|
||||||
*
|
|
||||||
* @param runList
|
|
||||||
* list of recipes or roles to assign. syntax is
|
|
||||||
* {@code recipe[name]} and {@code role[name]}
|
|
||||||
*
|
*
|
||||||
* @param group
|
* @param group
|
||||||
* corresponds to a configured
|
* The group where the given bootstrap configuration will be
|
||||||
* {@link org.jclouds.chef.config.ChefProperties#CHEF_BOOTSTRAP_DATABAG
|
* applied.
|
||||||
* databag} where run_list and other information are stored
|
* @param bootstrapConfig
|
||||||
* @deprecated use
|
* The configuration to be applied to the nodes in the group.
|
||||||
* {@link ChefService#updateBootstrapConfigForGroup(Iterable, String)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
void updateBootstrapConfigForGroup(String group, BootstrapConfig bootstrapConfig);
|
||||||
void updateRunListForGroup(Iterable<String> runList, String group);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* assigns a run list to all nodes bootstrapped with a certain group
|
* assigns a run list to all nodes bootstrapped with a certain group
|
||||||
|
@ -102,9 +96,11 @@ public interface ChefService {
|
||||||
* corresponds to a configured
|
* corresponds to a configured
|
||||||
* {@link org.jclouds.chef.config.ChefProperties#CHEF_BOOTSTRAP_DATABAG
|
* {@link org.jclouds.chef.config.ChefProperties#CHEF_BOOTSTRAP_DATABAG
|
||||||
* databag} where run_list and other information are stored
|
* databag} where run_list and other information are stored
|
||||||
* @see #makeChefApiBootstrapScriptForTag
|
* @deprecated Use {link
|
||||||
|
* {@link #updateBootstrapConfigForGroup(String, BootstrapConfig)}
|
||||||
*/
|
*/
|
||||||
public void updateBootstrapConfigForGroup(Iterable<String> runList, String group);
|
@Deprecated
|
||||||
|
void updateBootstrapConfigForGroup(Iterable<String> runList, String group);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* assigns a run list to all nodes bootstrapped with a certain group, and
|
* assigns a run list to all nodes bootstrapped with a certain group, and
|
||||||
|
@ -123,9 +119,11 @@ public interface ChefService {
|
||||||
* corresponds to a configured
|
* corresponds to a configured
|
||||||
* {@link org.jclouds.chef.config.ChefProperties#CHEF_BOOTSTRAP_DATABAG
|
* {@link org.jclouds.chef.config.ChefProperties#CHEF_BOOTSTRAP_DATABAG
|
||||||
* databag} where run_list and other information are stored
|
* databag} where run_list and other information are stored
|
||||||
* @see #makeChefApiBootstrapScriptForTag
|
* @deprecated Use {link
|
||||||
|
* {@link #updateBootstrapConfigForGroup(String, BootstrapConfig)}
|
||||||
*/
|
*/
|
||||||
public void updateBootstrapConfigForGroup(Iterable<String> runList, JsonBall jsonAttributes, String group);
|
@Deprecated
|
||||||
|
void updateBootstrapConfigForGroup(Iterable<String> runList, JsonBall jsonAttributes, String group);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param group
|
* @param group
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.jclouds.chef.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.collect.Iterables.addAll;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jclouds.domain.JsonBall;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures how the nodes in a group will bootstrap.
|
||||||
|
*
|
||||||
|
* @author Ignasi Barrera
|
||||||
|
* @since 1.7
|
||||||
|
*/
|
||||||
|
public class BootstrapConfig {
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private List<String> runList = Lists.newArrayList();
|
||||||
|
private String environment;
|
||||||
|
private JsonBall attribtues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the run list that will be executed in the nodes of the group.
|
||||||
|
*/
|
||||||
|
public Builder runList(Iterable<String> runList) {
|
||||||
|
addAll(this.runList, checkNotNull(runList, "runList"));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the environment where the nodes in the group will be deployed.
|
||||||
|
*/
|
||||||
|
public Builder environment(String environment) {
|
||||||
|
this.environment = checkNotNull(environment, "environment");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the attributes that will be populated to the deployed nodes.
|
||||||
|
*/
|
||||||
|
public Builder attributes(JsonBall attributes) {
|
||||||
|
this.attribtues = checkNotNull(attributes, "attributes");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BootstrapConfig build() {
|
||||||
|
return new BootstrapConfig(runList, Optional.fromNullable(environment), Optional.fromNullable(attribtues));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> runList = Lists.newArrayList();
|
||||||
|
private Optional<String> environment;
|
||||||
|
private Optional<JsonBall> attribtues;
|
||||||
|
|
||||||
|
protected BootstrapConfig(List<String> runList, Optional<String> environment, Optional<JsonBall> attribtues) {
|
||||||
|
this.runList = checkNotNull(runList, "runList");
|
||||||
|
this.environment = checkNotNull(environment, "environment");
|
||||||
|
this.attribtues = checkNotNull(attribtues, "attributes");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getRunList() {
|
||||||
|
return runList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getEnvironment() {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<JsonBall> getAttribtues() {
|
||||||
|
return attribtues;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -44,11 +44,13 @@ import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,6 +84,7 @@ public class GroupToBootScript implements Function<String, Statement> {
|
||||||
this.validatorCredential = checkNotNull(validatorCredential, validatorCredential);
|
this.validatorCredential = checkNotNull(validatorCredential, validatorCredential);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Statement apply(String group) {
|
public Statement apply(String group) {
|
||||||
checkNotNull(group, "group");
|
checkNotNull(group, "group");
|
||||||
String validatorClientName = validatorName.get();
|
String validatorClientName = validatorName.get();
|
||||||
|
@ -94,6 +97,10 @@ public class GroupToBootScript implements Function<String, Statement> {
|
||||||
throw propagate(e);
|
throw propagate(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, JsonBall> config = json.fromJson(bootstrapConfig.toString(),
|
||||||
|
BootstrapConfigForGroup.BOOTSTRAP_CONFIG_TYPE);
|
||||||
|
Optional<JsonBall> environment = Optional.fromNullable(config.get("environment"));
|
||||||
|
|
||||||
String chefConfigDir = "{root}etc{fs}chef";
|
String chefConfigDir = "{root}etc{fs}chef";
|
||||||
Statement createChefConfigDir = exec("{md} " + chefConfigDir);
|
Statement createChefConfigDir = exec("{md} " + chefConfigDir);
|
||||||
Statement createClientRb = appendFile(chefConfigDir + "{fs}client.rb", ImmutableList.of("require 'rubygems'",
|
Statement createClientRb = appendFile(chefConfigDir + "{fs}client.rb", ImmutableList.of("require 'rubygems'",
|
||||||
|
@ -106,10 +113,15 @@ public class GroupToBootScript implements Function<String, Statement> {
|
||||||
Splitter.on('\n').split(Pems.pem(validatorKey)));
|
Splitter.on('\n').split(Pems.pem(validatorKey)));
|
||||||
|
|
||||||
String chefBootFile = chefConfigDir + "{fs}first-boot.json";
|
String chefBootFile = chefConfigDir + "{fs}first-boot.json";
|
||||||
|
|
||||||
Statement createFirstBoot = appendFile(chefBootFile, Collections.singleton(json.toJson(bootstrapConfig)));
|
Statement createFirstBoot = appendFile(chefBootFile, Collections.singleton(json.toJson(bootstrapConfig)));
|
||||||
|
|
||||||
Statement runChef = exec("chef-client -j " + chefBootFile);
|
ImmutableMap.Builder<String, String> options = ImmutableMap.builder();
|
||||||
|
options.put("-j", chefBootFile);
|
||||||
|
if (environment.isPresent()) {
|
||||||
|
options.put("-E", environment.get().toString());
|
||||||
|
}
|
||||||
|
String strOptions = Joiner.on(' ').withKeyValueSeparator(" ").join(options.build());
|
||||||
|
Statement runChef = exec("chef-client " + strOptions);
|
||||||
|
|
||||||
return newStatementList(installChefGems, createChefConfigDir, createClientRb, createValidationPem,
|
return newStatementList(installChefGems, createChefConfigDir, createClientRb, createValidationPem,
|
||||||
createFirstBoot, runChef);
|
createFirstBoot, runChef);
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.jclouds.chef.ChefApi;
|
||||||
import org.jclouds.chef.ChefContext;
|
import org.jclouds.chef.ChefContext;
|
||||||
import org.jclouds.chef.ChefService;
|
import org.jclouds.chef.ChefService;
|
||||||
import org.jclouds.chef.config.ChefProperties;
|
import org.jclouds.chef.config.ChefProperties;
|
||||||
|
import org.jclouds.chef.domain.BootstrapConfig;
|
||||||
import org.jclouds.chef.domain.Client;
|
import org.jclouds.chef.domain.Client;
|
||||||
import org.jclouds.chef.domain.CookbookVersion;
|
import org.jclouds.chef.domain.CookbookVersion;
|
||||||
import org.jclouds.chef.domain.DatabagItem;
|
import org.jclouds.chef.domain.DatabagItem;
|
||||||
|
@ -63,10 +64,8 @@ import org.jclouds.logging.Logger;
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Optional;
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.io.InputSupplier;
|
import com.google.common.io.InputSupplier;
|
||||||
|
@ -210,26 +209,15 @@ public class BaseChefService implements ChefService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
public void updateBootstrapConfigForGroup(String group, BootstrapConfig bootstrapConfig) {
|
||||||
public void updateRunListForGroup(Iterable<String> runList, String group) {
|
|
||||||
updateBootstrapConfigForGroup(runList, group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateBootstrapConfigForGroup(Iterable<String> runList, String group) {
|
|
||||||
updateBootstrapConfigForGroup(runList, null, group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateBootstrapConfigForGroup(Iterable<String> runList, @Nullable JsonBall jsonAttributes, String group) {
|
|
||||||
try {
|
try {
|
||||||
api.createDatabag(databag);
|
api.createDatabag(databag);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String bootstrapConfig = buildBootstrapConfiguration(runList, Optional.fromNullable(jsonAttributes));
|
String jsonConfig = buildBootstrapConfiguration(bootstrapConfig);
|
||||||
DatabagItem runlist = new DatabagItem(group, bootstrapConfig);
|
DatabagItem runlist = new DatabagItem(group, jsonConfig);
|
||||||
|
|
||||||
if (api.getDatabagItem(databag, group) == null) {
|
if (api.getDatabagItem(databag, group) == null) {
|
||||||
api.createDatabagItem(databag, runlist);
|
api.createDatabagItem(databag, runlist);
|
||||||
|
@ -238,6 +226,19 @@ public class BaseChefService implements ChefService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void updateBootstrapConfigForGroup(Iterable<String> runList, String group) {
|
||||||
|
updateBootstrapConfigForGroup(runList, null, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void updateBootstrapConfigForGroup(Iterable<String> runList, @Nullable JsonBall jsonAttributes, String group) {
|
||||||
|
updateBootstrapConfigForGroup(group, BootstrapConfig.builder().runList(runList).attributes(jsonAttributes)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRunListForGroup(String group) {
|
public List<String> getRunListForGroup(String group) {
|
||||||
return runListForGroup.apply(group);
|
return runListForGroup.apply(group);
|
||||||
|
@ -261,18 +262,23 @@ public class BaseChefService implements ChefService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
String buildBootstrapConfiguration(Iterable<String> runList, Optional<JsonBall> jsonAttributes) {
|
String buildBootstrapConfiguration(BootstrapConfig bootstrapConfig) {
|
||||||
checkNotNull(runList, "runList must not be null");
|
checkNotNull(bootstrapConfig, "bootstrapConfig must not be null");
|
||||||
checkNotNull(jsonAttributes, "jsonAttributes must not be null");
|
|
||||||
|
|
||||||
Map<String, Object> bootstrapConfig = Maps.newHashMap();
|
Map<String, Object> configMap = Maps.newHashMap();
|
||||||
bootstrapConfig.put("run_list", Lists.newArrayList(runList));
|
configMap.put("run_list", bootstrapConfig.getRunList());
|
||||||
if (jsonAttributes.isPresent()) {
|
|
||||||
Map<String, Object> attributes = json.fromJson(jsonAttributes.get().toString(),
|
if (bootstrapConfig.getEnvironment().isPresent()) {
|
||||||
BootstrapConfigForGroup.BOOTSTRAP_CONFIG_TYPE);
|
configMap.put("environment", bootstrapConfig.getEnvironment().get());
|
||||||
bootstrapConfig.putAll(attributes);
|
|
||||||
}
|
}
|
||||||
return json.toJson(bootstrapConfig);
|
|
||||||
|
if (bootstrapConfig.getAttribtues().isPresent()) {
|
||||||
|
Map<String, Object> attributes = json.fromJson(bootstrapConfig.getAttribtues().get().toString(),
|
||||||
|
BootstrapConfigForGroup.BOOTSTRAP_CONFIG_TYPE);
|
||||||
|
configMap.putAll(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.toJson(configMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -289,4 +295,5 @@ public class BaseChefService implements ChefService {
|
||||||
public Iterable<? extends Environment> listEnvironmentsNamed(Iterable<String> names) {
|
public Iterable<? extends Environment> listEnvironmentsNamed(Iterable<String> names) {
|
||||||
return listEnvironments.execute(names);
|
return listEnvironments.execute(names);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.jclouds.rest.annotations.ApiVersion;
|
||||||
import org.jclouds.scriptbuilder.domain.OsFamily;
|
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||||
import org.jclouds.scriptbuilder.domain.ShellToken;
|
import org.jclouds.scriptbuilder.domain.ShellToken;
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
|
@ -63,22 +64,29 @@ import com.google.inject.name.Names;
|
||||||
@Test(groups = "unit", testName = "GroupToBootScriptTest")
|
@Test(groups = "unit", testName = "GroupToBootScriptTest")
|
||||||
public class GroupToBootScriptTest {
|
public class GroupToBootScriptTest {
|
||||||
|
|
||||||
Injector injector = Guice.createInjector(new AbstractModule() {
|
private Json json;
|
||||||
@Override
|
private Statement installChefGems;
|
||||||
protected void configure() {
|
private Optional<String> validatorName;
|
||||||
bind(String.class).annotatedWith(ApiVersion.class).toInstance(ChefApi.VERSION);
|
|
||||||
bind(String.class).annotatedWith(Names.named(CHEF_UPDATE_GEM_SYSTEM)).toInstance("true");
|
|
||||||
bind(String.class).annotatedWith(Names.named(CHEF_UPDATE_GEMS)).toInstance("true");
|
|
||||||
}
|
|
||||||
}, new ChefParserModule(), new GsonModule(), new ChefBootstrapModule());
|
|
||||||
|
|
||||||
Json json = injector.getInstance(Json.class);
|
@BeforeClass
|
||||||
Statement installChefGems = injector.getInstance(Key.get(Statement.class, Names.named("installChefGems")));
|
public void setup() {
|
||||||
Optional<String> validatorName = Optional.<String> of("chef-validator");
|
Injector injector = Guice.createInjector(new AbstractModule() {
|
||||||
Optional<PrivateKey> validatorCredential = Optional.<PrivateKey> of(createMock(PrivateKey.class));
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(String.class).annotatedWith(ApiVersion.class).toInstance(ChefApi.VERSION);
|
||||||
|
bind(String.class).annotatedWith(Names.named(CHEF_UPDATE_GEM_SYSTEM)).toInstance("true");
|
||||||
|
bind(String.class).annotatedWith(Names.named(CHEF_UPDATE_GEMS)).toInstance("true");
|
||||||
|
}
|
||||||
|
}, new ChefParserModule(), new GsonModule(), new ChefBootstrapModule());
|
||||||
|
|
||||||
|
json = injector.getInstance(Json.class);
|
||||||
|
installChefGems = injector.getInstance(Key.get(Statement.class, Names.named("installChefGems")));
|
||||||
|
validatorName = Optional.<String> of("chef-validator");
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expectedExceptions = IllegalStateException.class)
|
@Test(expectedExceptions = IllegalStateException.class)
|
||||||
public void testMustHaveValidatorName() {
|
public void testMustHaveValidatorName() {
|
||||||
|
Optional<PrivateKey> validatorCredential = Optional.of(createMock(PrivateKey.class));
|
||||||
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
||||||
CacheLoader.from(Functions.forMap(ImmutableMap.<String, DatabagItem> of())), installChefGems,
|
CacheLoader.from(Functions.forMap(ImmutableMap.<String, DatabagItem> of())), installChefGems,
|
||||||
Optional.<String> absent(), validatorCredential);
|
Optional.<String> absent(), validatorCredential);
|
||||||
|
@ -95,6 +103,7 @@ public class GroupToBootScriptTest {
|
||||||
|
|
||||||
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Key 'foo' not present in map")
|
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Key 'foo' not present in map")
|
||||||
public void testMustHaveRunScriptsName() {
|
public void testMustHaveRunScriptsName() {
|
||||||
|
Optional<PrivateKey> validatorCredential = Optional.of(createMock(PrivateKey.class));
|
||||||
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
||||||
CacheLoader.from(Functions.forMap(ImmutableMap.<String, DatabagItem> of())), installChefGems,
|
CacheLoader.from(Functions.forMap(ImmutableMap.<String, DatabagItem> of())), installChefGems,
|
||||||
validatorName, validatorCredential);
|
validatorName, validatorCredential);
|
||||||
|
@ -103,6 +112,7 @@ public class GroupToBootScriptTest {
|
||||||
|
|
||||||
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "null value in entry: foo=null")
|
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "null value in entry: foo=null")
|
||||||
public void testMustHaveRunScriptsValue() {
|
public void testMustHaveRunScriptsValue() {
|
||||||
|
Optional<PrivateKey> validatorCredential = Optional.of(createMock(PrivateKey.class));
|
||||||
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
||||||
CacheLoader.from(Functions.forMap(ImmutableMap.<String, DatabagItem> of("foo", (DatabagItem) null))),
|
CacheLoader.from(Functions.forMap(ImmutableMap.<String, DatabagItem> of("foo", (DatabagItem) null))),
|
||||||
installChefGems, validatorName, validatorCredential);
|
installChefGems, validatorName, validatorCredential);
|
||||||
|
@ -110,6 +120,7 @@ public class GroupToBootScriptTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOneRecipe() throws IOException {
|
public void testOneRecipe() throws IOException {
|
||||||
|
Optional<PrivateKey> validatorCredential = Optional.of(createMock(PrivateKey.class));
|
||||||
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
||||||
CacheLoader.from(Functions.forMap(ImmutableMap.<String, JsonBall> of("foo", new JsonBall(
|
CacheLoader.from(Functions.forMap(ImmutableMap.<String, JsonBall> of("foo", new JsonBall(
|
||||||
"{\"tomcat6\":{\"ssl_port\":8433},\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}")))),
|
"{\"tomcat6\":{\"ssl_port\":8433},\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}")))),
|
||||||
|
@ -131,4 +142,29 @@ public class GroupToBootScriptTest {
|
||||||
|
|
||||||
verify(validatorKey);
|
verify(validatorKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testOneRecipeAndEnvironment() throws IOException {
|
||||||
|
Optional<PrivateKey> validatorCredential = Optional.of(createMock(PrivateKey.class));
|
||||||
|
GroupToBootScript fn = new GroupToBootScript(Suppliers.ofInstance(URI.create("http://localhost:4000")), json,
|
||||||
|
CacheLoader.from(Functions.forMap(ImmutableMap.<String, JsonBall> of("foo", new JsonBall(
|
||||||
|
"{\"tomcat6\":{\"ssl_port\":8433},\"environment\":\"env\","
|
||||||
|
+ "\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}")))), installChefGems,
|
||||||
|
validatorName, validatorCredential);
|
||||||
|
|
||||||
|
PrivateKey validatorKey = validatorCredential.get();
|
||||||
|
expect(validatorKey.getEncoded()).andReturn(PemsTest.PRIVATE_KEY.getBytes());
|
||||||
|
replay(validatorKey);
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
fn.apply("foo").render(OsFamily.UNIX),
|
||||||
|
Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
|
||||||
|
Charsets.UTF_8)
|
||||||
|
+ Resources.toString(
|
||||||
|
Resources.getResource("test_install_rubygems." + ShellToken.SH.to(OsFamily.UNIX)),
|
||||||
|
Charsets.UTF_8)
|
||||||
|
+ "gem install chef --no-rdoc --no-ri\n"
|
||||||
|
+ Resources.toString(Resources.getResource("bootstrap-env.sh"), Charsets.UTF_8));
|
||||||
|
|
||||||
|
verify(validatorKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
||||||
|
|
||||||
import org.jclouds.ContextBuilder;
|
import org.jclouds.ContextBuilder;
|
||||||
import org.jclouds.chef.ChefApiMetadata;
|
import org.jclouds.chef.ChefApiMetadata;
|
||||||
|
import org.jclouds.chef.domain.BootstrapConfig;
|
||||||
import org.jclouds.chef.filters.SignedHeaderAuthTest;
|
import org.jclouds.chef.filters.SignedHeaderAuthTest;
|
||||||
import org.jclouds.chef.util.RunListBuilder;
|
import org.jclouds.chef.util.RunListBuilder;
|
||||||
import org.jclouds.domain.JsonBall;
|
import org.jclouds.domain.JsonBall;
|
||||||
|
@ -32,7 +33,6 @@ import org.jclouds.rest.internal.BaseRestApiTest.MockModule;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
|
@ -57,39 +57,47 @@ public class BaseChefServiceTest {
|
||||||
chefService = injector.getInstance(BaseChefService.class);
|
chefService = injector.getInstance(BaseChefService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "runList must not be null")
|
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "bootstrapConfig must not be null")
|
||||||
public void testBuildBootstrapConfigurationWithNullRunlist() {
|
public void testBuildBootstrapConfigurationWithNullConfig() {
|
||||||
chefService.buildBootstrapConfiguration(null, null);
|
chefService.buildBootstrapConfiguration(null);
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "jsonAttributes must not be null")
|
|
||||||
public void testBuildBootstrapConfigurationWithNullJsonAttributes() {
|
|
||||||
chefService.buildBootstrapConfiguration(ImmutableList.<String> of(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBuildBootstrapConfigurationWithEmptyRunlist() {
|
public void testBuildBootstrapConfigurationWithEmptyRunlist() {
|
||||||
String config = chefService
|
BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runList(ImmutableList.<String> of()).build();
|
||||||
.buildBootstrapConfiguration(ImmutableList.<String> of(), Optional.<JsonBall> absent());
|
String config = chefService.buildBootstrapConfiguration(bootstrapConfig);
|
||||||
assertEquals(config, "{\"run_list\":[]}");
|
assertEquals(config, "{\"run_list\":[]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBuildBootstrapConfigurationWithRunlist() {
|
public void testBuildBootstrapConfigurationWithRunlist() {
|
||||||
List<String> runlist = new RunListBuilder().addRecipe("apache2").addRole("webserver").build();
|
List<String> runlist = new RunListBuilder().addRecipe("apache2").addRole("webserver").build();
|
||||||
String config = chefService.buildBootstrapConfiguration(runlist, Optional.<JsonBall> absent());
|
BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runList(runlist).build();
|
||||||
|
String config = chefService.buildBootstrapConfiguration(bootstrapConfig);
|
||||||
assertEquals(config, "{\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}");
|
assertEquals(config, "{\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBuildBootstrapConfigurationWithRunlistAndEmptyAttributes() {
|
public void testBuildBootstrapConfigurationWithRunlistAndEmptyAttributes() {
|
||||||
List<String> runlist = new RunListBuilder().addRecipe("apache2").addRole("webserver").build();
|
List<String> runlist = new RunListBuilder().addRecipe("apache2").addRole("webserver").build();
|
||||||
String config = chefService.buildBootstrapConfiguration(runlist, Optional.of(new JsonBall("{}")));
|
BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runList(runlist).attributes(new JsonBall("{}"))
|
||||||
|
.build();
|
||||||
|
String config = chefService.buildBootstrapConfiguration(bootstrapConfig);
|
||||||
assertEquals(config, "{\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}");
|
assertEquals(config, "{\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBuildBootstrapConfigurationWithRunlistAndAttributes() {
|
public void testBuildBootstrapConfigurationWithRunlistAndAttributes() {
|
||||||
List<String> runlist = new RunListBuilder().addRecipe("apache2").addRole("webserver").build();
|
List<String> runlist = new RunListBuilder().addRecipe("apache2").addRole("webserver").build();
|
||||||
String config = chefService.buildBootstrapConfiguration(runlist,
|
BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runList(runlist)
|
||||||
Optional.of(new JsonBall("{\"tomcat6\":{\"ssl_port\":8433}}")));
|
.attributes(new JsonBall("{\"tomcat6\":{\"ssl_port\":8433}}")).build();
|
||||||
|
String config = chefService.buildBootstrapConfiguration(bootstrapConfig);
|
||||||
assertEquals(config, "{\"tomcat6\":{\"ssl_port\":8433},\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}");
|
assertEquals(config, "{\"tomcat6\":{\"ssl_port\":8433},\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBuildBootstrapConfigurationWithRunlistAndAttributesAndEnvironment() {
|
||||||
|
List<String> runlist = new RunListBuilder().addRecipe("apache2").addRole("webserver").build();
|
||||||
|
BootstrapConfig bootstrapConfig = BootstrapConfig.builder().runList(runlist)
|
||||||
|
.attributes(new JsonBall("{\"tomcat6\":{\"ssl_port\":8433}}")).environment("env").build();
|
||||||
|
String config = chefService.buildBootstrapConfiguration(bootstrapConfig);
|
||||||
|
assertEquals(config,
|
||||||
|
"{\"tomcat6\":{\"ssl_port\":8433},\"environment\":\"env\",\"run_list\":[\"recipe[apache2]\",\"role[webserver]\"]}");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
mkdir -p /etc/chef
|
||||||
|
cat >> /etc/chef/client.rb <<-'END_OF_JCLOUDS_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 "chef-validator"
|
||||||
|
chef_server_url "http://localhost:4000"
|
||||||
|
END_OF_JCLOUDS_FILE
|
||||||
|
cat >> /etc/chef/validation.pem <<-'END_OF_JCLOUDS_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_JCLOUDS_FILE
|
||||||
|
cat >> /etc/chef/first-boot.json <<-'END_OF_JCLOUDS_FILE'
|
||||||
|
{"tomcat6":{"ssl_port":8433},"environment":"env","run_list":["recipe[apache2]","role[webserver]"]}
|
||||||
|
END_OF_JCLOUDS_FILE
|
||||||
|
chef-client -j /etc/chef/first-boot.json -E "env"
|
Loading…
Reference in New Issue