blob: a7fd4253b17bc3a47c839f0aa1f823f51286256d [file] [log] [blame]
/*
* 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.scriptbuilder;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.concat;
import static java.lang.String.format;
import static org.jclouds.scriptbuilder.ScriptBuilder.call;
import static org.jclouds.scriptbuilder.ScriptBuilder.findPid;
import static org.jclouds.scriptbuilder.ScriptBuilder.forget;
import static org.jclouds.scriptbuilder.domain.Statements.createRunScript;
import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import static org.jclouds.scriptbuilder.domain.Statements.kill;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import static org.jclouds.scriptbuilder.domain.Statements.switchArg;
import java.util.Map;
import org.jclouds.scriptbuilder.domain.AcceptsStatementVisitor;
import org.jclouds.scriptbuilder.domain.CreateRunScript;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.domain.StatementVisitor;
import com.google.common.base.Objects;
import com.google.common.collect.ForwardingObject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Creates an init script file
*/
public class InitScript extends ForwardingObject implements Statement, AcceptsStatementVisitor {
public static Builder builder() {
return new Builder();
}
public static class Builder {
protected String instanceName;
protected String instanceHome = "{tmp}{fs}{varl}INSTANCE_NAME{varr}";
protected String logDir = "{varl}INSTANCE_HOME{varr}";
protected Map<String, String> exports = ImmutableMap.of();
protected StatementList init = new StatementList();
protected StatementList run = new StatementList();
/**
* @see InitScript#getInstanceName()
*/
public Builder name(String instanceName) {
this.instanceName = checkNotNull(instanceName, "INSTANCE_NAME");
return this;
}
/**
* @see InitScript#getInstanceHome()
*/
public Builder home(String instanceHome) {
this.instanceHome = checkNotNull(instanceHome, "INSTANCE_HOME");
return this;
}
/**
* @see InitScript#getLogDir()
*/
public Builder logDir(String logDir) {
this.logDir = checkNotNull(logDir, "LOG_DIR");
return this;
}
/**
* @param exports keys are the variables to export in UPPER_UNDERSCORE case format
* @see InitScript#getExportedVariables()
*/
public Builder exportVariables(Map<String, String> exports) {
this.exports = ImmutableMap.copyOf(checkNotNull(exports, "exports"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(Statement run) {
this.run = new StatementList(checkNotNull(run, "run"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(Statement... run) {
this.run = new StatementList(checkNotNull(run, "run"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(Iterable<Statement> run) {
this.run = new StatementList(checkNotNull(run, "run"));
return this;
}
/**
* @see InitScript#getRun()
*/
public Builder run(StatementList run) {
this.run = checkNotNull(run, "run");
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(Statement init) {
this.init = new StatementList(checkNotNull(init, "init"));
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(Statement... init) {
this.init = new StatementList(checkNotNull(init, "init"));
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(Iterable<Statement> init) {
this.init = new StatementList(checkNotNull(init, "init"));
return this;
}
/**
* @see InitScript#getInit()
*/
public Builder init(StatementList init) {
this.init = checkNotNull(init, "init");
return this;
}
public InitScript build() {
return new InitScript(instanceName, instanceHome, logDir, exports, init, run);
}
}
protected final String instanceName;
protected final String instanceHome;
protected final String logDir;
protected final Map<String, String> exports;
protected final StatementList init;
protected final StatementList run;
protected final ScriptBuilder delegate;
/**
* @param exports keys are the variables to export in UPPER_UNDERSCORE case format
*/
protected InitScript(String instanceName, String instanceHome, String logDir, Map<String, String> exports,
StatementList init, StatementList run) {
this.instanceName = checkNotNull(instanceName, "INSTANCE_NAME");
this.instanceHome = checkNotNull(instanceHome, "INSTANCE_HOME");
this.logDir = checkNotNull(logDir, "LOG_DIR");
this.exports = ImmutableMap.<String, String> copyOf(checkNotNull(exports, "exports"));
this.init = checkNotNull(init, "init");
this.run = checkNotNull(run, "run");
checkArgument(!run.delegate().isEmpty(), "you must specify at least one statement to run");
this.delegate = makeInitScriptStatement(instanceName, instanceHome, logDir, exports, init, run);
}
/**
*
* @param exports keys are the variables to export in UPPER_UNDERSCORE case format
*/
public static ScriptBuilder makeInitScriptStatement(String instanceName, String instanceHome, String logDir,
Map<String, String> exports, StatementList init, StatementList run) {
Map<String, String> defaultExports = ImmutableMap.of("INSTANCE_NAME", instanceName, "INSTANCE_HOME", instanceHome,
"LOG_DIR", logDir);
String exitStatusFile = format("%s/rc", logDir);
run = new StatementList(ImmutableList.<Statement> builder().add(interpret("rm -f " + exitStatusFile))
.add(interpret(format("trap 'echo $?>%s' 0 1 2 3 15", exitStatusFile))).addAll(run.delegate()).build());
CreateRunScript createRunScript = createRunScript(instanceName,
concat(exports.keySet(), defaultExports.keySet()), "{varl}INSTANCE_HOME{varr}", run);
return new ScriptBuilder()
.addEnvironmentVariableScope("default", defaultExports)
.addEnvironmentVariableScope(instanceName, exports)
.addStatement(
switchArg(
1,
new ImmutableMap.Builder<String, Statement>()
.put("init", newStatementList(call("default"), call(instanceName), init, createRunScript))
.put("status",
newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"),
interpret("echo {varl}FOUND_PID{varr}{lf}")))
.put("stop",
newStatementList(call("default"), findPid("{varl}INSTANCE_NAME{varr}"), kill()))
.put("start",
newStatementList(
call("default"),
forget("{varl}INSTANCE_NAME{varr}",
"{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}",
"{varl}LOG_DIR{varr}")))
.put("stdout",
newStatementList(call("default"),
interpret("cat {varl}LOG_DIR{varr}{fs}stdout.log{lf}")))
.put("stderr",
newStatementList(call("default"),
interpret("cat {varl}LOG_DIR{varr}{fs}stderr.log{lf}")))
.put("exitstatus",
newStatementList(call("default"),
interpret("[ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc")))
.put("tail",
newStatementList(call("default"),
interpret("tail {varl}LOG_DIR{varr}{fs}stdout.log{lf}")))
.put("tailerr",
newStatementList(call("default"),
interpret("tail {varl}LOG_DIR{varr}{fs}stderr.log{lf}")))
.put("run",
newStatementList(call("default"),
interpret("{varl}INSTANCE_HOME{varr}{fs}{varl}INSTANCE_NAME{varr}.{sh}{lf}")))
.build()));
}
/**
*
* @return what will be bound to the INSTANCE_NAME variable, and uniquely
* identifies the process
*/
public String getInstanceName() {
return instanceName;
}
/**
* default {@code /tmp/$INSTANCE_NAME}
* <br/>
* <h3>note</h3> The parent directory
* should be set with unix sticky-bit or otherwise made available to all
* users. Otherwise, new instances by other users may fail due to not being
* able to create a directory. This is why the default is set to {@code /tmp}
*
* @return what will be bound to the INSTANCE_HOME variable, and represents
* the working directory of the instance
*/
public String getInstanceHome() {
return instanceHome;
}
/**
* default {@code $INSTANCE_HOME}
*
* @return what will be bound to the LOG_DIR variable, and represents where
* stdout and stderr.logs are written.
*/
public String getLogDir() {
return logDir;
}
/**
*
* @return statements that will be executed upon the init command
*/
public StatementList getInitStatement() {
return init;
}
/**
*
* @return statements that will be executed upon the run or start commands
*/
public StatementList getRunStatement() {
return init;
}
@Override
public int hashCode() {
return Objects.hashCode(instanceName);
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof InitScript)) {
return false;
}
InitScript that = (InitScript) obj;
return equal(this.instanceName, that.instanceName);
}
@Override
public String toString() {
return toStringHelper(this).add("INSTANCE_NAME", instanceName).toString();
}
@Override
public void accept(StatementVisitor visitor) {
delegate().accept(visitor);
}
@Override
public Iterable<String> functionDependencies(OsFamily family) {
return delegate().functionDependencies(family);
}
@Override
public String render(OsFamily family) {
return delegate().render(family);
}
@Override
protected ScriptBuilder delegate() {
return delegate;
}
}