mirror of https://github.com/apache/jclouds.git
Issue 126: first cut at init builder, complete with shell script generation
git-svn-id: http://jclouds.googlecode.com/svn/trunk@2338 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
a52209bfc8
commit
c66eb4c389
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* 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.initbuilder;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jclouds.initbuilder.domain.OsFamily;
|
||||
import org.jclouds.initbuilder.domain.ShellToken;
|
||||
import org.jclouds.initbuilder.util.Utils;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Creates a start script.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class InitBuilder {
|
||||
|
||||
@VisibleForTesting
|
||||
Map<String, Map<String, String>> switchExec = Maps.newHashMap();
|
||||
|
||||
@VisibleForTesting
|
||||
Map<String, String> variables = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* Adds a switch statement to the script. If its value is found, it will invoke the corresponding
|
||||
* action.
|
||||
*
|
||||
* <p/>
|
||||
* Ex. variable is {@code 1} - the first argument to the script<br/>
|
||||
* and valueToActions is {"start" -> "echo hello", "stop" -> "echo goodbye"}<br/>
|
||||
* the script created will respond accordingly:<br/>
|
||||
* {@code ./script start }<br/>
|
||||
* << returns hello<br/>
|
||||
* {@code ./script stop }<br/>
|
||||
* << returns goodbye<br/>
|
||||
*
|
||||
* @param variable
|
||||
* - shell variable to switch on
|
||||
* @param valueToActions
|
||||
* - case statements, if the value of the variable matches a key, the corresponding
|
||||
* value will be invoked.
|
||||
*/
|
||||
public InitBuilder switchOn(String variable, Map<String, String> valueToActions) {
|
||||
switchExec.put(checkNotNull(variable, "variable"), checkNotNull(valueToActions,
|
||||
"valueToActions"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a variable inside the script
|
||||
*/
|
||||
public InitBuilder export(String name, String value) {
|
||||
variables.put(checkNotNull(name, "name"), checkNotNull(value, "value"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* builds the shell script, by adding the following
|
||||
* <ol>
|
||||
* <li>shell declaration line</li>
|
||||
* <li>variable exports</li>
|
||||
* <li>case/switch</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param osFamily
|
||||
* whether to write a cmd or bash script.
|
||||
*/
|
||||
public String build(OsFamily osFamily) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(ShellToken.SHEBANG.to(osFamily));
|
||||
builder.append(ShellToken.ZERO_PATH.to(osFamily));
|
||||
builder.append(Utils.writeVariableExporters(variables, osFamily));
|
||||
for (Entry<String, Map<String, String>> entry : switchExec.entrySet()) {
|
||||
builder.append(Utils.writeSwitch(entry.getKey(), entry.getValue(), osFamily));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,8 @@
|
|||
*/
|
||||
package org.jclouds.initbuilder.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
|
@ -45,15 +47,15 @@ public class InitMetadata {
|
|||
|
||||
public InitMetadata(String name, String platformHome, URI endPoint, String startDir,
|
||||
String stopDir, String configDir, String dataDir, String logDir, String goldDir) {
|
||||
this.name = name;
|
||||
this.platformHome = platformHome;
|
||||
this.name = checkNotNull(name, "name");
|
||||
this.platformHome = checkNotNull(platformHome, "platformHome");
|
||||
this.endPoint = endPoint;
|
||||
this.startDir = startDir;
|
||||
this.stopDir = stopDir;
|
||||
this.configDir = configDir;
|
||||
this.dataDir = dataDir;
|
||||
this.logDir = logDir;
|
||||
this.goldDir = goldDir;
|
||||
this.startDir = checkNotNull(startDir, "startDir");
|
||||
this.stopDir = checkNotNull(stopDir, "stopDir");
|
||||
this.configDir = checkNotNull(configDir, "configDir");
|
||||
this.dataDir = checkNotNull(dataDir, "dataDir");
|
||||
this.logDir = checkNotNull(logDir, "logDir");
|
||||
this.goldDir = checkNotNull(goldDir, "goldDir");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,6 +71,7 @@ public class InitMetadata {
|
|||
public String getStopDir() {
|
||||
return stopDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where the platform that this process is an instance of is located. This is analogous to the
|
||||
* CATALINA_HOME on the tomcat platform.
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* 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.initbuilder.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Constants used in operating suy
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public enum ShellToken {
|
||||
|
||||
FS, PS, LF, SH, SOURCE, REM, ARGS, VARSTART, VAREND, SHEBANG, ZERO_PATH, EXE;
|
||||
|
||||
private static final Map<OsFamily, Map<String, String>> familyToTokenValueMap = new MapMaker()
|
||||
.makeComputingMap(new Function<OsFamily, Map<String, String>>() {
|
||||
|
||||
@Override
|
||||
public Map<String, String> apply(OsFamily from) {
|
||||
Map<String, String> map = Maps.newHashMap();
|
||||
for (ShellToken token : ShellToken.values()) {
|
||||
map.put(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, token
|
||||
.toString()), token.to(from));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
public static Map<String, String> tokenValueMap(OsFamily family) {
|
||||
return familyToTokenValueMap.get(family);
|
||||
}
|
||||
|
||||
public String to(OsFamily family) {
|
||||
checkNotNull(family, "family");
|
||||
switch (this) {
|
||||
case FS:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "\\";
|
||||
case UNIX:
|
||||
return "/";
|
||||
}
|
||||
case PS:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return ";";
|
||||
case UNIX:
|
||||
return ":";
|
||||
}
|
||||
case LF:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "\r\n";
|
||||
case UNIX:
|
||||
return "\n";
|
||||
}
|
||||
case SH:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "cmd";
|
||||
case UNIX:
|
||||
return "bash";
|
||||
}
|
||||
case SOURCE:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "@call";
|
||||
case UNIX:
|
||||
return ".";
|
||||
}
|
||||
case REM:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "@rem";
|
||||
case UNIX:
|
||||
return "#";
|
||||
}
|
||||
case ARGS:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "%*";
|
||||
case UNIX:
|
||||
return "$@";
|
||||
}
|
||||
case VARSTART:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "%";
|
||||
case UNIX:
|
||||
return "$";
|
||||
}
|
||||
case VAREND:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "%";
|
||||
case UNIX:
|
||||
return "";
|
||||
}
|
||||
case SHEBANG:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "@echo off\r\n";
|
||||
case UNIX:
|
||||
return "#!/bin/bash\n";
|
||||
}
|
||||
case ZERO_PATH:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "set PATH=c:\\windows\\;C:\\windows\\system32\r\n";
|
||||
case UNIX:
|
||||
return "export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin\n";
|
||||
}
|
||||
case EXE:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return ".exe";
|
||||
case UNIX:
|
||||
return "";
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedOperationException("token " + this + " not configured");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -97,4 +97,29 @@ public class Utils {
|
|||
}
|
||||
return initializers.toString();
|
||||
}
|
||||
|
||||
public static final Map<OsFamily, String> OS_TO_SWITCH_PATTERN = ImmutableMap.of(OsFamily.UNIX,
|
||||
"case ${variable} in\n", OsFamily.WINDOWS, "goto CASE%{variable}\r\n");
|
||||
|
||||
public static final Map<OsFamily, String> OS_TO_END_SWITCH_PATTERN = ImmutableMap.of(
|
||||
OsFamily.UNIX, "esac\n", OsFamily.WINDOWS, ":END_SWITCH\r\n");
|
||||
|
||||
public static final Map<OsFamily, String> OS_TO_CASE_PATTERN = ImmutableMap.of(OsFamily.UNIX,
|
||||
"{value})\n {action}\n ;;\n", OsFamily.WINDOWS,
|
||||
":CASE_{value}\r\n {action}\r\n GOTO END_SWITCH\r\n");
|
||||
|
||||
public static String writeSwitch(String variable, Map<String, String> valueToActions,
|
||||
OsFamily family) {
|
||||
StringBuilder switchClause = new StringBuilder();
|
||||
switchClause.append(replaceTokens(OS_TO_SWITCH_PATTERN.get(family), ImmutableMap.of(
|
||||
"variable", CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, variable))));
|
||||
|
||||
for (Entry<String, String> entry : valueToActions.entrySet()) {
|
||||
switchClause.append(replaceTokens(OS_TO_CASE_PATTERN.get(family), ImmutableMap.of("value",
|
||||
entry.getKey(), "action", entry.getValue())));
|
||||
}
|
||||
|
||||
switchClause.append(OS_TO_END_SWITCH_PATTERN.get(family));
|
||||
return switchClause.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package org.jclouds.initbuilder;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import org.jclouds.initbuilder.domain.OsFamily;
|
||||
import org.jclouds.initbuilder.domain.ShellToken;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.io.Resources;
|
||||
|
||||
/**
|
||||
* Tests possible uses of InitBuilder
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class InitBuilderTest {
|
||||
|
||||
InitBuilder testScriptBuilder = new InitBuilder().switchOn("1",
|
||||
ImmutableMap.of("start", "echo started", "stop", "echo stopped")).export("javaHome",
|
||||
"/apps/jdk1.6");
|
||||
|
||||
@Test
|
||||
public void testBuildSimpleWindows() throws MalformedURLException, IOException {
|
||||
assertEquals(testScriptBuilder.build(OsFamily.WINDOWS), CharStreams.toString(Resources
|
||||
.newReaderSupplier(Resources.getResource("test_script."
|
||||
+ ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildSimpleUNIX() throws MalformedURLException, IOException {
|
||||
assertEquals(testScriptBuilder.build(OsFamily.UNIX), CharStreams.toString(Resources
|
||||
.newReaderSupplier(Resources.getResource("test_script."
|
||||
+ ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSwitchOn() {
|
||||
InitBuilder builder = new InitBuilder();
|
||||
builder.switchOn("1", ImmutableMap.of("start", "echo started", "stop", "echo stopped"));
|
||||
assertEquals(builder.switchExec, ImmutableMap.of("1", ImmutableMap.of("start",
|
||||
"echo started", "stop", "echo stopped")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSwitchOn() {
|
||||
InitBuilder builder = new InitBuilder();
|
||||
assertEquals(builder.switchExec.size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExport() {
|
||||
InitBuilder builder = new InitBuilder();
|
||||
builder.export("javaHome", "/apps/jdk1.6");
|
||||
assertEquals(builder.variables, ImmutableMap.of("javaHome", "/apps/jdk1.6"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoExport() {
|
||||
InitBuilder builder = new InitBuilder();
|
||||
assertEquals(builder.variables.size(), 0);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testExportNPE() {
|
||||
new InitBuilder().export(null, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* 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.initbuilder.domain;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "initbuilder.ShellTokenTest")
|
||||
public class ShellTokenTest {
|
||||
|
||||
public void testTokenValueMapUNIX() {
|
||||
Map<String, String> expected = new ImmutableMap.Builder<String, String>().put("fs", "/").put(
|
||||
"ps", ":").put("lf", "\n").put("sh", "bash").put("source", ".").put("rem", "#").put(
|
||||
"args", "$@").put("varstart", "$").put("varend", "").put("shebang", "#!/bin/bash\n")
|
||||
.put("zeroPath", "export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin\n")
|
||||
.put("exe", "").build();
|
||||
|
||||
assertEquals(ShellToken.tokenValueMap(OsFamily.UNIX), expected);
|
||||
}
|
||||
|
||||
public void testTokenValueMapWindows() {
|
||||
Map<String, String> expected = new ImmutableMap.Builder<String, String>().put("fs", "\\")
|
||||
.put("ps", ";").put("lf", "\r\n").put("sh", "cmd").put("source", "@call").put("rem",
|
||||
"@rem").put("args", "%*").put("varstart", "%").put("varend", "%").put(
|
||||
"shebang", "@echo off\r\n").put("zeroPath",
|
||||
"set PATH=c:\\windows\\;C:\\windows\\system32\r\n").put("exe", ".exe")
|
||||
.build();
|
||||
|
||||
assertEquals(ShellToken.tokenValueMap(OsFamily.WINDOWS), expected);
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ import com.google.common.collect.ImmutableMap;
|
|||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "jclouds.UtilsTest")
|
||||
@Test(groups = "unit", testName = "initbuilder.UtilsTest")
|
||||
public class UtilsTest {
|
||||
|
||||
public void testReplaceTokens() throws UnsupportedEncodingException {
|
||||
|
@ -52,4 +52,17 @@ public class UtilsTest {
|
|||
"-Xms128m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError"), OsFamily.WINDOWS),
|
||||
"set MAVEN_OPTS=-Xms128m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError\r\n");
|
||||
}
|
||||
|
||||
public void testWriteSwitchUNIX() {
|
||||
assertEquals(Utils.writeSwitch("i", ImmutableMap.of("0", "echo hello zero", "1",
|
||||
"echo hello one"), OsFamily.UNIX),
|
||||
"case $I in\n0)\n echo hello zero\n ;;\n1)\n echo hello one\n ;;\nesac\n");
|
||||
}
|
||||
|
||||
public void testWriteSwitchWindows() {
|
||||
assertEquals(
|
||||
Utils.writeSwitch("i", ImmutableMap
|
||||
.of("0", "echo hello zero", "1", "echo hello one"), OsFamily.WINDOWS),
|
||||
"goto CASE%I\r\n:CASE_0\r\n echo hello zero\r\n GOTO END_SWITCH\r\n:CASE_1\r\n echo hello one\r\n GOTO END_SWITCH\r\n:END_SWITCH\r\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin
|
||||
export JAVA_HOME="/apps/jdk1.6"
|
||||
case $1 in
|
||||
start)
|
||||
echo started
|
||||
;;
|
||||
stop)
|
||||
echo stopped
|
||||
;;
|
||||
esac
|
|
@ -0,0 +1,11 @@
|
|||
@echo off
|
||||
set PATH=c:\windows\;C:\windows\system32
|
||||
set JAVA_HOME=/apps/jdk1.6
|
||||
goto CASE%1
|
||||
:CASE_start
|
||||
echo started
|
||||
GOTO END_SWITCH
|
||||
:CASE_stop
|
||||
echo stopped
|
||||
GOTO END_SWITCH
|
||||
:END_SWITCH
|
Loading…
Reference in New Issue