EMMA Coverage Report (generated Wed Aug 10 12:30:04 EDT 2011)
[all classes][org.jclouds.compute.callables]

COVERAGE SUMMARY FOR SOURCE FILE [RunScriptOnNodeAsInitScriptUsingSsh.java]

nameclass, %method, %block, %line, %
RunScriptOnNodeAsInitScriptUsingSsh.java0%   (0/2)0%   (0/16)0%   (0/543)0%   (0/68)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class RunScriptOnNodeAsInitScriptUsingSsh0%   (0/1)0%   (0/14)0%   (0/532)0%   (0/66)
RunScriptOnNodeAsInitScriptUsingSsh (Function, NodeMetadata, Statement, RunSc... 0%   (0/1)0%   (0/77)0%   (0/14)
call (): ExecResponse 0%   (0/1)0%   (0/31)0%   (0/5)
createInitScript (String, Statement): InitBuilder 0%   (0/1)0%   (0/19)0%   (0/2)
doCall (): ExecResponse 0%   (0/1)0%   (0/127)0%   (0/15)
execScriptAsDefaultUser (String): String 0%   (0/1)0%   (0/15)0%   (0/1)
execScriptAsRoot (String): String 0%   (0/1)0%   (0/66)0%   (0/6)
getNode (): NodeMetadata 0%   (0/1)0%   (0/3)0%   (0/1)
getStatement (): Statement 0%   (0/1)0%   (0/3)0%   (0/1)
init (): RunScriptOnNode 0%   (0/1)0%   (0/10)0%   (0/2)
refreshSshIfNewAdminCredentialsConfigured (AdminAccess): void 0%   (0/1)0%   (0/51)0%   (0/7)
runAction (String): ExecResponse 0%   (0/1)0%   (0/52)0%   (0/6)
runCommand (String): ExecResponse 0%   (0/1)0%   (0/40)0%   (0/3)
setupLinkToInitFile (): void 0%   (0/1)0%   (0/20)0%   (0/2)
toString (): String 0%   (0/1)0%   (0/18)0%   (0/1)
     
class RunScriptOnNodeAsInitScriptUsingSsh$10%   (0/1)0%   (0/2)0%   (0/11)0%   (0/3)
RunScriptOnNodeAsInitScriptUsingSsh$1 (RunScriptOnNodeAsInitScriptUsingSsh): ... 0%   (0/1)0%   (0/6)0%   (0/1)
visit (AdminAccess): void 0%   (0/1)0%   (0/5)0%   (0/2)

1/**
2 *
3 * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4 *
5 * ====================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 * ====================================================================
18 */
19package org.jclouds.compute.callables;
20 
21import static com.google.common.base.Preconditions.checkNotNull;
22import static com.google.common.base.Preconditions.checkState;
23 
24import java.util.Collections;
25 
26import javax.annotation.Resource;
27import javax.inject.Named;
28 
29import org.jclouds.compute.domain.ExecResponse;
30import org.jclouds.compute.domain.NodeMetadata;
31import org.jclouds.compute.domain.NodeMetadataBuilder;
32import org.jclouds.compute.options.RunScriptOptions;
33import org.jclouds.compute.reference.ComputeServiceConstants;
34import org.jclouds.logging.Logger;
35import org.jclouds.scriptbuilder.InitBuilder;
36import org.jclouds.scriptbuilder.domain.AdminAccessVisitor;
37import org.jclouds.scriptbuilder.domain.AppendFile;
38import org.jclouds.scriptbuilder.domain.OsFamily;
39import org.jclouds.scriptbuilder.domain.Statement;
40import org.jclouds.scriptbuilder.domain.Statements;
41import org.jclouds.scriptbuilder.statements.login.AdminAccess;
42import org.jclouds.ssh.SshClient;
43import org.jclouds.ssh.SshException;
44 
45import com.google.common.annotations.VisibleForTesting;
46import com.google.common.base.Function;
47import com.google.common.base.Objects;
48import com.google.common.base.Splitter;
49import com.google.inject.Inject;
50import com.google.inject.assistedinject.Assisted;
51import com.google.inject.assistedinject.AssistedInject;
52 
53/**
54 * 
55 * @author Adrian Cole
56 */
57public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode {
58   public static final String PROPERTY_INIT_SCRIPT_PATTERN = "jclouds.compute.init-script-pattern";
59   @Resource
60   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
61   protected Logger logger = Logger.NULL;
62 
63   protected final Function<NodeMetadata, SshClient> sshFactory;
64   protected NodeMetadata node;
65   protected final InitBuilder init;
66   protected final boolean runAsRoot;
67   protected final String initFile;
68 
69   protected SshClient ssh;
70 
71   /**
72    * determines the naming convention of init scripts.
73    * 
74    * ex. {@code /tmp/init-%s}
75    */
76   @Inject(optional = true)
77   @Named(PROPERTY_INIT_SCRIPT_PATTERN)
78   private String initScriptPattern = "/tmp/init-%s";
79 
80   @AssistedInject
81   public RunScriptOnNodeAsInitScriptUsingSsh(Function<NodeMetadata, SshClient> sshFactory,
82            @Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) {
83      this.sshFactory = checkNotNull(sshFactory, "sshFactory");
84      this.node = checkNotNull(node, "node");
85      String name = options.getTaskName();
86      if (name == null) {
87         if (checkNotNull(script, "script") instanceof InitBuilder)
88            name = InitBuilder.class.cast(script).getInstanceName();
89         else
90            name = "jclouds-script-" + System.currentTimeMillis();
91      }
92      this.init = checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script)
93               : createInitScript(name, script);
94      this.initFile = String.format(initScriptPattern, name);
95      this.runAsRoot = options.shouldRunAsRoot();
96   }
97 
98   public static InitBuilder createInitScript(String name, Statement script) {
99      String path = "/tmp/" + name;
100      return new InitBuilder(name, path, path, Collections.<String, String> emptyMap(), Collections.singleton(script));
101   }
102 
103   @Override
104   public ExecResponse call() {
105      checkState(ssh != null, "please call init() before invoking call");
106      try {
107         ssh.connect();
108         return doCall();
109      } finally {
110         if (ssh != null)
111            ssh.disconnect();
112      }
113   }
114 
115   @Override
116   public RunScriptOnNode init() {
117      ssh = sshFactory.apply(node);
118      return this;
119   }
120 
121   public void refreshSshIfNewAdminCredentialsConfigured(AdminAccess input) {
122      if (input.getAdminCredentials() != null && input.shouldGrantSudoToAdminUser()) {
123         ssh.disconnect();
124         logger.debug(">> reconnecting as %s@%s", input.getAdminCredentials().identity, ssh.getHostAddress());
125         ssh = sshFactory.apply(node = NodeMetadataBuilder.fromNodeMetadata(node).adminPassword(null).credentials(
126                  input.getAdminCredentials()).build());
127         ssh.connect();
128         setupLinkToInitFile();
129      }
130   }
131 
132   /**
133    * ssh client is initialized through this call.
134    */
135   protected ExecResponse doCall() {
136      try {
137         ssh.put(initFile, init.render(OsFamily.UNIX));
138      } catch (SshException e) {
139         // If there's a problem with the sftp configuration, we can try via ssh exec
140         if (logger.isTraceEnabled())
141            logger.warn(e, "<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage());
142         else
143            logger.warn("<< (%s) problem using sftp [%s], attempting via sshexec", ssh.toString(), e.getMessage());
144         ssh.disconnect();
145         ssh.connect();
146         ssh.exec("rm " + initFile);
147         ssh.exec(Statements.appendFile(initFile, Splitter.on('\n').split(init.render(OsFamily.UNIX)),
148                  AppendFile.MARKER + "_" + init.getInstanceName()).render(OsFamily.UNIX));
149      }
150 
151      ssh.exec("chmod 755 " + initFile);
152      setupLinkToInitFile();
153 
154      runAction("init");
155      init.getInitStatement().accept(new AdminAccessVisitor() {
156 
157         @Override
158         public void visit(AdminAccess input) {
159            refreshSshIfNewAdminCredentialsConfigured(input);
160         }
161 
162      });
163      return runAction("start");
164   }
165 
166   protected void setupLinkToInitFile() {
167      ssh.exec(String.format("ln -fs %s %s", initFile, init.getInstanceName()));
168   }
169 
170   protected ExecResponse runAction(String action) {
171      ExecResponse returnVal;
172      String command = (runAsRoot) ? execScriptAsRoot(action) : execScriptAsDefaultUser(action);
173      returnVal = runCommand(command);
174      if (logger.isTraceEnabled())
175         logger.trace("<< %s[%s]", action, returnVal);
176      else
177         logger.debug("<< %s(%d)", action, returnVal.getExitCode());
178      return returnVal;
179   }
180 
181   protected ExecResponse runCommand(String command) {
182      ExecResponse returnVal;
183      logger.debug(">> running [%s] as %s@%s", command.replace(node.getAdminPassword() != null ? node
184               .getAdminPassword() : "XXXXX", "XXXXX"), ssh.getUsername(), ssh.getHostAddress());
185      returnVal = ssh.exec(command);
186      return returnVal;
187   }
188 
189   @VisibleForTesting
190   public String execScriptAsRoot(String action) {
191      String command;
192      if (node.getCredentials().identity.equals("root")) {
193         command = "./" + init.getInstanceName() + " " + action;
194      } else if (node.getAdminPassword() != null) {
195         command = String.format("echo '%s'|sudo -S ./%s %s", node.getAdminPassword(), init.getInstanceName(), action);
196      } else {
197         command = "sudo ./" + init.getInstanceName() + " " + action;
198      }
199      return command;
200   }
201 
202   protected String execScriptAsDefaultUser(String action) {
203      return "./" + init.getInstanceName() + " " + action;
204   }
205 
206   public NodeMetadata getNode() {
207      return node;
208   }
209 
210   @Override
211   public String toString() {
212      return Objects.toStringHelper(this).add("node", node).add("name", init.getInstanceName())
213            .add("runAsRoot", runAsRoot).toString();
214   }
215 
216   @Override
217   public Statement getStatement() {
218      return init;
219   }
220 
221}

[all classes][org.jclouds.compute.callables]
EMMA 2.0.5312 (C) Vladimir Roubtsov