1 | /** |
2 | * Licensed to jclouds, Inc. (jclouds) under one or more |
3 | * contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. jclouds licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. 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, |
13 | * software distributed under the License is distributed on an |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | * KIND, either express or implied. See the License for the |
16 | * specific language governing permissions and limitations |
17 | * under the License. |
18 | */ |
19 | package org.jclouds.compute.callables; |
20 | |
21 | import static com.google.common.base.Preconditions.checkNotNull; |
22 | import static com.google.common.base.Preconditions.checkState; |
23 | |
24 | import javax.annotation.PostConstruct; |
25 | import javax.annotation.Resource; |
26 | import javax.inject.Named; |
27 | |
28 | import org.jclouds.compute.domain.ExecResponse; |
29 | import org.jclouds.compute.domain.NodeMetadata; |
30 | import org.jclouds.compute.reference.ComputeServiceConstants; |
31 | import org.jclouds.logging.Logger; |
32 | import org.jclouds.scriptbuilder.InitBuilder; |
33 | import org.jclouds.ssh.SshClient; |
34 | |
35 | import com.google.common.annotations.VisibleForTesting; |
36 | import com.google.common.base.Function; |
37 | import com.google.common.base.Objects; |
38 | import com.google.common.base.Predicates; |
39 | import com.google.common.collect.ImmutableSet; |
40 | |
41 | /** |
42 | * |
43 | * @author Adrian Cole |
44 | */ |
45 | public class SudoAwareInitManager { |
46 | @Resource |
47 | @Named(ComputeServiceConstants.COMPUTE_LOGGER) |
48 | protected Logger computeLogger = Logger.NULL; |
49 | protected Logger logger = Logger.NULL; |
50 | protected NodeMetadata node; |
51 | protected final InitBuilder init; |
52 | protected final boolean runAsRoot; |
53 | protected final Function<NodeMetadata, SshClient> sshFactory; |
54 | protected SshClient ssh; |
55 | |
56 | public SudoAwareInitManager(Function<NodeMetadata, SshClient> sshFactory, boolean runAsRoot, NodeMetadata node, |
57 | InitBuilder init) { |
58 | this.sshFactory = checkNotNull(sshFactory, "sshFactory"); |
59 | this.runAsRoot = runAsRoot; |
60 | this.node = checkNotNull(node, "node"); |
61 | this.init = checkNotNull(init, "init"); |
62 | } |
63 | |
64 | @PostConstruct |
65 | public SudoAwareInitManager init() { |
66 | ssh = sshFactory.apply(node); |
67 | return this; |
68 | } |
69 | |
70 | public ExecResponse refreshAndRunAction(String action) { |
71 | checkState(ssh != null, "please call init() before invoking call"); |
72 | try { |
73 | ssh.connect(); |
74 | return runAction(action); |
75 | } finally { |
76 | if (ssh != null) |
77 | ssh.disconnect(); |
78 | } |
79 | } |
80 | |
81 | public ExecResponse runAction(String action) { |
82 | ExecResponse returnVal; |
83 | String command = (runAsRoot && Predicates.in(ImmutableSet.of("start", "stop", "run")).apply(action)) ? execScriptAsRoot(action) |
84 | : execScriptAsDefaultUser(action); |
85 | returnVal = runCommand(command); |
86 | if ("status".equals(action)) |
87 | logger.trace("<< %s(%d)", action, returnVal.getExitCode()); |
88 | else if (computeLogger.isTraceEnabled()) |
89 | computeLogger.trace("<< %s[%s]", action, returnVal); |
90 | else |
91 | computeLogger.debug("<< %s(%d)", action, returnVal.getExitCode()); |
92 | return returnVal; |
93 | } |
94 | |
95 | ExecResponse runCommand(String command) { |
96 | String statement = String.format(">> running [%s] as %s@%s", command.replace( |
97 | node.getAdminPassword() != null ? node.getAdminPassword() : "XXXXX", "XXXXX"), ssh.getUsername(), ssh |
98 | .getHostAddress()); |
99 | if (command.endsWith("status")) |
100 | logger.trace(statement); |
101 | else |
102 | computeLogger.debug(statement); |
103 | return ssh.exec(command); |
104 | } |
105 | |
106 | @VisibleForTesting |
107 | String execScriptAsRoot(String action) { |
108 | String command; |
109 | if (node.getCredentials().identity.equals("root")) { |
110 | command = "./" + init.getInstanceName() + " " + action; |
111 | } else if (node.getAdminPassword() != null) { |
112 | command = String.format("echo '%s'|sudo -S ./%s %s", node.getAdminPassword(), init.getInstanceName(), action); |
113 | } else { |
114 | command = "sudo ./" + init.getInstanceName() + " " + action; |
115 | } |
116 | return command; |
117 | } |
118 | |
119 | protected String execScriptAsDefaultUser(String action) { |
120 | return "./" + init.getInstanceName() + " " + action; |
121 | } |
122 | |
123 | public NodeMetadata getNode() { |
124 | return node; |
125 | } |
126 | |
127 | @Override |
128 | public String toString() { |
129 | return Objects.toStringHelper(this).add("node", node).add("name", init.getInstanceName()).add("runAsRoot", |
130 | runAsRoot).toString(); |
131 | } |
132 | |
133 | public InitBuilder getStatement() { |
134 | return init; |
135 | } |
136 | } |