1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase;
20
21 import com.sun.jersey.api.client.Client;
22 import com.sun.jersey.api.client.ClientResponse;
23 import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.conf.Configured;
29 import org.apache.hadoop.util.ReflectionUtils;
30 import org.codehaus.jackson.JsonNode;
31 import org.codehaus.jackson.map.ObjectMapper;
32
33 import javax.ws.rs.core.MediaType;
34 import javax.ws.rs.core.Response;
35 import javax.ws.rs.core.UriBuilder;
36 import javax.xml.ws.http.HTTPException;
37 import java.io.IOException;
38 import java.net.URI;
39 import java.util.HashMap;
40 import java.util.Map;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class RESTApiClusterManager extends Configured implements ClusterManager {
64
65
66 private static final String REST_API_CLUSTER_MANAGER_HOSTNAME =
67 "hbase.it.clustermanager.restapi.hostname";
68 private static final String REST_API_CLUSTER_MANAGER_USERNAME =
69 "hbase.it.clustermanager.restapi.username";
70 private static final String REST_API_CLUSTER_MANAGER_PASSWORD =
71 "hbase.it.clustermanager.restapi.password";
72 private static final String REST_API_CLUSTER_MANAGER_CLUSTER_NAME =
73 "hbase.it.clustermanager.restapi.clustername";
74
75
76 private static final String DEFAULT_SERVER_HOSTNAME = "http://localhost:7180";
77 private static final String DEFAULT_SERVER_USERNAME = "admin";
78 private static final String DEFAULT_SERVER_PASSWORD = "admin";
79 private static final String DEFAULT_CLUSTER_NAME = "Cluster 1";
80
81
82
83 private String serverHostname;
84 private String serverUsername;
85 private String serverPassword;
86 private String clusterName;
87
88
89
90 private static final String API_VERSION = "v6";
91
92
93 private Client client = Client.create();
94
95
96
97 private ClusterManager hBaseClusterManager;
98
99 private static final Log LOG = LogFactory.getLog(RESTApiClusterManager.class);
100
101 RESTApiClusterManager() {
102 hBaseClusterManager = ReflectionUtils.newInstance(HBaseClusterManager.class,
103 new IntegrationTestingUtility().getConfiguration());
104 }
105
106 @Override
107 public void setConf(Configuration conf) {
108 super.setConf(conf);
109 if (conf == null) {
110
111 return;
112 }
113 serverHostname = conf.get(REST_API_CLUSTER_MANAGER_HOSTNAME, DEFAULT_SERVER_HOSTNAME);
114 serverUsername = conf.get(REST_API_CLUSTER_MANAGER_USERNAME, DEFAULT_SERVER_USERNAME);
115 serverPassword = conf.get(REST_API_CLUSTER_MANAGER_PASSWORD, DEFAULT_SERVER_PASSWORD);
116 clusterName = conf.get(REST_API_CLUSTER_MANAGER_CLUSTER_NAME, DEFAULT_CLUSTER_NAME);
117
118
119 client.addFilter(new HTTPBasicAuthFilter(serverUsername, serverPassword));
120 }
121
122 @Override
123 public void start(ServiceType service, String hostname, int port) throws IOException {
124 performClusterManagerCommand(service, hostname, RoleCommand.START);
125 }
126
127 @Override
128 public void stop(ServiceType service, String hostname, int port) throws IOException {
129 performClusterManagerCommand(service, hostname, RoleCommand.STOP);
130 }
131
132 @Override
133 public void restart(ServiceType service, String hostname, int port) throws IOException {
134 performClusterManagerCommand(service, hostname, RoleCommand.RESTART);
135 }
136
137 @Override
138 public boolean isRunning(ServiceType service, String hostname, int port) throws IOException {
139 String serviceName = getServiceName(roleServiceType.get(service));
140 String hostId = getHostId(hostname);
141 String roleState = getRoleState(serviceName, service.toString(), hostId);
142 String healthSummary = getHealthSummary(serviceName, service.toString(), hostId);
143 boolean isRunning = false;
144
145
146
147 if ("STARTED".equals(roleState) && "GOOD".equals(healthSummary)) {
148 isRunning = true;
149 }
150
151 return isRunning;
152 }
153
154 @Override
155 public void kill(ServiceType service, String hostname, int port) throws IOException {
156 hBaseClusterManager.kill(service, hostname, port);
157 }
158
159 @Override
160 public void suspend(ServiceType service, String hostname, int port) throws IOException {
161 hBaseClusterManager.suspend(service, hostname, port);
162 }
163
164 @Override
165 public void resume(ServiceType service, String hostname, int port) throws IOException {
166 hBaseClusterManager.resume(service, hostname, port);
167 }
168
169
170
171 private void performClusterManagerCommand(ServiceType role, String hostname, RoleCommand command)
172 throws IOException {
173 LOG.info("Performing " + command + " command against " + role + " on " + hostname + "...");
174 String serviceName = getServiceName(roleServiceType.get(role));
175 String hostId = getHostId(hostname);
176 String roleName = getRoleName(serviceName, role.toString(), hostId);
177 doRoleCommand(serviceName, roleName, command);
178 }
179
180
181 private void doRoleCommand(String serviceName, String roleName, RoleCommand roleCommand) {
182 URI uri = UriBuilder.fromUri(serverHostname)
183 .path("api")
184 .path(API_VERSION)
185 .path("clusters")
186 .path(clusterName)
187 .path("services")
188 .path(serviceName)
189 .path("roleCommands")
190 .path(roleCommand.toString())
191 .build();
192 String body = "{ \"items\": [ \"" + roleName + "\" ] }";
193 LOG.info("Executing POST against " + uri + " with body " + body + "...");
194 ClientResponse response = client.resource(uri)
195 .type(MediaType.APPLICATION_JSON)
196 .post(ClientResponse.class, body);
197
198 int statusCode = response.getStatus();
199 if (statusCode != Response.Status.OK.getStatusCode()) {
200 throw new HTTPException(statusCode);
201 }
202 }
203
204
205 private String getHealthSummary(String serviceName, String roleType, String hostId)
206 throws IOException {
207 return getRolePropertyValue(serviceName, roleType, hostId, "healthSummary");
208 }
209
210
211 private String getHostId(String hostname) throws IOException {
212 String hostId = null;
213
214 URI uri = UriBuilder.fromUri(serverHostname)
215 .path("api")
216 .path(API_VERSION)
217 .path("hosts")
218 .build();
219 JsonNode hosts = getJsonNodeFromURIGet(uri);
220 if (hosts != null) {
221
222 for (JsonNode host : hosts) {
223 if (host.get("hostname").getTextValue().equals(hostname)) {
224 hostId = host.get("hostId").getTextValue();
225 break;
226 }
227 }
228 } else {
229 hostId = null;
230 }
231
232 return hostId;
233 }
234
235
236 private JsonNode getJsonNodeFromURIGet(URI uri) throws IOException {
237 LOG.info("Executing GET against " + uri + "...");
238 ClientResponse response = client.resource(uri)
239 .accept(MediaType.APPLICATION_JSON_TYPE)
240 .get(ClientResponse.class);
241
242 int statusCode = response.getStatus();
243 if (statusCode != Response.Status.OK.getStatusCode()) {
244 throw new HTTPException(statusCode);
245 }
246
247 return new ObjectMapper().readTree(response.getEntity(String.class)).get("items");
248 }
249
250
251 private String getRoleName(String serviceName, String roleType, String hostId)
252 throws IOException {
253 return getRolePropertyValue(serviceName, roleType, hostId, "name");
254 }
255
256
257 private String getRolePropertyValue(String serviceName, String roleType, String hostId,
258 String property) throws IOException {
259 String roleValue = null;
260 URI uri = UriBuilder.fromUri(serverHostname)
261 .path("api")
262 .path(API_VERSION)
263 .path("clusters")
264 .path(clusterName)
265 .path("services")
266 .path(serviceName)
267 .path("roles")
268 .build();
269 JsonNode roles = getJsonNodeFromURIGet(uri);
270 if (roles != null) {
271
272 for (JsonNode role : roles) {
273 if (role.get("hostRef").get("hostId").getTextValue().equals(hostId) &&
274 role.get("type")
275 .getTextValue()
276 .toLowerCase()
277 .equals(roleType.toLowerCase())) {
278 roleValue = role.get(property).getTextValue();
279 break;
280 }
281 }
282 }
283
284 return roleValue;
285 }
286
287
288 private String getRoleState(String serviceName, String roleType, String hostId)
289 throws IOException {
290 return getRolePropertyValue(serviceName, roleType, hostId, "roleState");
291 }
292
293
294 private String getServiceName(Service service) throws IOException {
295 String serviceName = null;
296 URI uri = UriBuilder.fromUri(serverHostname)
297 .path("api")
298 .path(API_VERSION)
299 .path("clusters")
300 .path(clusterName)
301 .path("services")
302 .build();
303 JsonNode services = getJsonNodeFromURIGet(uri);
304 if (services != null) {
305
306 for (JsonNode serviceEntry : services) {
307 if (serviceEntry.get("type").getTextValue().equals(service.toString())) {
308 serviceName = serviceEntry.get("name").getTextValue();
309 break;
310 }
311 }
312 }
313
314 return serviceName;
315 }
316
317
318
319
320
321
322
323
324 private enum RoleCommand {
325 START, STOP, RESTART;
326
327
328 @Override
329 public String toString() {
330 return name().toLowerCase();
331 }
332 }
333
334
335
336
337 private static Map<ServiceType, Service> roleServiceType = new HashMap<ServiceType, Service>();
338 static {
339 roleServiceType.put(ServiceType.HADOOP_NAMENODE, Service.HDFS);
340 roleServiceType.put(ServiceType.HADOOP_DATANODE, Service.HDFS);
341 roleServiceType.put(ServiceType.HADOOP_JOBTRACKER, Service.MAPREDUCE);
342 roleServiceType.put(ServiceType.HADOOP_TASKTRACKER, Service.MAPREDUCE);
343 roleServiceType.put(ServiceType.HBASE_MASTER, Service.HBASE);
344 roleServiceType.put(ServiceType.HBASE_REGIONSERVER, Service.HBASE);
345 }
346
347 private enum Service {
348 HBASE, HDFS, MAPREDUCE
349 }
350 }