Java tutorial
/* * 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 brooklyn.entity.chef; import static brooklyn.util.text.StringEscapes.BashStringEscapes.wrapBash; import static com.google.common.base.Preconditions.checkNotNull; import java.io.File; import java.util.List; import java.util.Map; import com.google.common.base.Strings; import com.google.common.net.HostAndPort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import brooklyn.entity.Entity; import brooklyn.entity.effector.EffectorTasks; import brooklyn.location.basic.SshMachineLocation; import brooklyn.util.collections.Jsonya; import brooklyn.util.collections.MutableList; import brooklyn.util.collections.MutableMap; import brooklyn.util.ssh.BashCommands; import brooklyn.util.task.system.ProcessTaskWrapper; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.gson.GsonBuilder; public class KnifeConvergeTaskFactory<RET> extends KnifeTaskFactory<RET> { private static final Logger log = LoggerFactory.getLogger(KnifeConvergeTaskFactory.class); protected Function<? super Entity, String> runList; protected Map<Object, Object> knifeAttributes = new MutableMap<Object, Object>(); protected List<String> extraBootstrapParameters = MutableList.of(); protected Boolean sudo; protected Boolean runTwice; protected String nodeName; protected Integer port; /** null means nothing specified, use user supplied or machine default; * false means use machine default (disallow user supplied); * true means use knife default (omit the argument and disallow user supplied) */ protected Boolean portOmittedToUseKnifeDefault; public KnifeConvergeTaskFactory(String taskName) { super(taskName); } @Override protected KnifeConvergeTaskFactory<RET> self() { return this; } /** construct the knife command, based on the settings on other methods * (called when instantiating the script, after all parameters sent) */ protected List<String> initialKnifeParameters() { // runs inside the task so can detect entity/machine at runtime MutableList<String> result = new MutableList<String>(); SshMachineLocation machine = EffectorTasks.findSshMachine(); result.add("bootstrap"); result.addAll(extraBootstrapParameters); HostAndPort hostAndPort = machine.getSshHostAndPort(); result.add(wrapBash(hostAndPort.getHostText())); Integer whichPort = knifeWhichPort(hostAndPort); if (whichPort != null) result.add("-p " + whichPort); result.add("-x " + wrapBash(checkNotNull(machine.getUser(), "user"))); File keyfile = ChefServerTasks.extractKeyFile(machine); if (keyfile != null) result.add("-i " + keyfile.getPath()); else result.add( "-P " + checkNotNull(machine.findPassword(), "No password or private key data for " + machine)); if (sudo != Boolean.FALSE) result.add("--sudo"); if (!Strings.isNullOrEmpty(nodeName)) { result.add("--node-name"); result.add(nodeName); } result.add("-r " + wrapBash(runList.apply(entity()))); if (!knifeAttributes.isEmpty()) result.add("-j " + wrapBash(new GsonBuilder().create().toJson(knifeAttributes))); return result; } /** whether knife should attempt to run twice; * see {@link ChefConfig#CHEF_RUN_CONVERGE_TWICE} */ public KnifeConvergeTaskFactory<RET> knifeRunTwice(boolean runTwice) { this.runTwice = runTwice; return self(); } /** whether to pass --sudo to knife; default true */ public KnifeConvergeTaskFactory<RET> knifeSudo(boolean sudo) { this.sudo = sudo; return self(); } /** what node name to pass to knife; default = null, meaning chef-client will pick the node name */ public KnifeConvergeTaskFactory<RET> knifeNodeName(String nodeName) { this.nodeName = nodeName; return self(); } /** tell knife to use an explicit port */ public KnifeConvergeTaskFactory<RET> knifePort(int port) { if (portOmittedToUseKnifeDefault != null) { log.warn("Port " + port + " specified to " + this + " for when already explicitly told to use a default (overriding previous); see subsequent warning for more details"); } this.port = port; return self(); } /** omit the port parameter altogether (let knife use its default) */ public KnifeConvergeTaskFactory<RET> knifePortUseKnifeDefault() { if (port != null) { log.warn("knifePortUseKnifeDefault specified to " + this + " when already told to use " + port + " explicitly (overriding previous); see subsequent warning for more details"); port = -1; } portOmittedToUseKnifeDefault = true; return self(); } /** use the default port known to brooklyn for the target machine for ssh */ public KnifeConvergeTaskFactory<RET> knifePortUseMachineSshPort() { if (port != null) { log.warn("knifePortUseMachineSshPort specified to " + this + " when already told to use " + port + " explicitly (overriding previous); see subsequent warning for more details"); port = -1; } portOmittedToUseKnifeDefault = false; return self(); } protected Integer knifeWhichPort(HostAndPort hostAndPort) { if (port == null) { if (Boolean.TRUE.equals(portOmittedToUseKnifeDefault)) // user has explicitly said to use knife default, omitting port here return null; // default is to use the machine port return hostAndPort.getPort(); } if (port == -1) { // port was supplied by user, then portDefault (true or false) port = null; Integer whichPort = knifeWhichPort(hostAndPort); log.warn("knife port conflicting instructions for " + this + " at entity " + entity() + " on " + hostAndPort + "; using default (" + whichPort + ")"); return whichPort; } if (portOmittedToUseKnifeDefault != null) { // portDefault was specified (true or false), then overridden with a port log.warn("knife port conflicting instructions for " + this + " at entity " + entity() + " on " + hostAndPort + "; using supplied port " + port); } // port was supplied by user, use that return port; } /** parameters to pass to knife after the bootstrap command */ public KnifeConvergeTaskFactory<RET> knifeAddExtraBootstrapParameters(String extraBootstrapParameter1, String... extraBootstrapParameters) { this.extraBootstrapParameters.add(extraBootstrapParameter1); for (String p : extraBootstrapParameters) this.extraBootstrapParameters.add(p); return self(); } /** function supplying the run list to be passed to knife, evaluated at the last moment */ public KnifeConvergeTaskFactory<RET> knifeRunList(Function<? super Entity, String> runList) { this.runList = runList; return self(); } public KnifeConvergeTaskFactory<RET> knifeRunList(String runList) { this.runList = Functions.constant(runList); return self(); } /** includes the given attributes in the attributes to be passed to chef; * when combining with other attributes, this uses {@link Jsonya} semantics to add * (a deep add, combining lists and maps) */ public KnifeConvergeTaskFactory<RET> knifeAddAttributes(Map<? extends Object, ? extends Object> attributes) { if (attributes != null && !attributes.isEmpty()) { Jsonya.of(knifeAttributes).add(attributes); } return self(); } protected String buildKnifeCommand(int knifeCommandIndex) { String result = super.buildKnifeCommand(knifeCommandIndex); if (Boolean.TRUE.equals(runTwice)) result = BashCommands.alternatives(result, result); return result; } @Override public <T2> KnifeConvergeTaskFactory<T2> returning(ScriptReturnType type) { return (KnifeConvergeTaskFactory<T2>) super.<T2>returning(type); } @Override public <RET2> KnifeConvergeTaskFactory<RET2> returning( Function<ProcessTaskWrapper<?>, RET2> resultTransformation) { return (KnifeConvergeTaskFactory<RET2>) super.returning(resultTransformation); } @Override public KnifeConvergeTaskFactory<Boolean> returningIsExitCodeZero() { return (KnifeConvergeTaskFactory<Boolean>) super.returningIsExitCodeZero(); } @Override public KnifeConvergeTaskFactory<String> requiringZeroAndReturningStdout() { return (KnifeConvergeTaskFactory<String>) super.requiringZeroAndReturningStdout(); } public KnifeConvergeTaskFactory<RET> knifeAddParameters(String word1, String... words) { super.knifeAddParameters(word1, words); return self(); } // TODO other methods from KnifeTaskFactory will return KTF class not KCTF; // should make it generic so it returns the right type... }