mirror of https://github.com/apache/jclouds.git
Extends JClouds' OpenStack Nova API with the Diagnostics command
The diagnostics command returns a collection of system information for the a given server. At the moment, there is no formal specification for this command. Therefore, it is returned as a Map of hypervisor specific entries and corresponding values. More information about the command can be viewed here [1] in the section "Server Diagnostics". [1] http://api.openstack.org/api-ref.html
This commit is contained in:
parent
718874e348
commit
99375844a6
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.openstack.nova.v2_0.features;
|
package org.jclouds.openstack.nova.v2_0.features;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -260,5 +261,24 @@ public interface ServerApi {
|
||||||
* the name of the metadata item
|
* the name of the metadata item
|
||||||
*/
|
*/
|
||||||
void deleteMetadata(String id, String key);
|
void deleteMetadata(String id, String key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get usage information about the server such as CPU usage, Memory and IO.
|
||||||
|
* The information returned by this method is dependent on the hypervisor
|
||||||
|
* in use by the OpenStack installation and whether that hypervisor supports
|
||||||
|
* this method. More information can be found in the
|
||||||
|
* <a href="http://api.openstack.org/api-ref.html"> OpenStack API
|
||||||
|
* reference</a>. <br/>
|
||||||
|
* At the moment the returned response is a generic map. In future versions
|
||||||
|
* of OpenStack this might be subject to change.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* id of the server
|
||||||
|
* @return A Map containing the collected values organized by key - value.
|
||||||
|
* @Beta
|
||||||
|
*/
|
||||||
|
Optional<Map<String, String>> getDiagnostics(String id);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.openstack.nova.v2_0.features;
|
package org.jclouds.openstack.nova.v2_0.features;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -63,8 +64,10 @@ import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
|
||||||
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||||
|
import org.jclouds.rest.functions.ReturnAbsentOn403Or404Or500;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.functions.internal.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides asynchronous access to Server via their REST API.
|
* Provides asynchronous access to Server via their REST API.
|
||||||
|
@ -319,4 +322,14 @@ public interface ServerAsyncApi {
|
||||||
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
|
||||||
ListenableFuture<Void> deleteMetadata(@PathParam("id") String id, @PathParam("key") String key);
|
ListenableFuture<Void> deleteMetadata(@PathParam("id") String id, @PathParam("key") String key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ServerApi#getDiagnostics
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/servers/{id}/diagnostics")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnAbsentOn403Or404Or500.class)
|
||||||
|
@ResponseParser(ParseDiagnostics.class)
|
||||||
|
ListenableFuture<Optional<Map<String, String>>> getDiagnostics(@PathParam("id") String id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012 jclouds.
|
||||||
|
*
|
||||||
|
* Licensed 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.openstack.nova.v2_0.functions.internal;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.http.functions.ParseJson;
|
||||||
|
import org.jclouds.json.internal.GsonWrapper;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Leander Beernaert
|
||||||
|
*/
|
||||||
|
public class ParseDiagnostics implements Function<HttpResponse, Optional <Map<String,String>>> {
|
||||||
|
|
||||||
|
|
||||||
|
private final ParseJson<Optional <Map<String,String>>> parser;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ParseDiagnostics(ParseJson<Optional <Map<String,String>>> parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional <Map<String,String>> apply(HttpResponse response) {
|
||||||
|
checkNotNull(response, "response");
|
||||||
|
return parser.apply(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ import org.testng.annotations.Test;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import org.jclouds.openstack.nova.v2_0.parse.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests annotation parsing of {@code ServerAsyncApi}
|
* Tests annotation parsing of {@code ServerAsyncApi}
|
||||||
|
@ -577,4 +578,46 @@ public class ServerApiExpectTest extends BaseNovaApiExpectTest {
|
||||||
apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").deleteMetadata(serverId, key);
|
apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").deleteMetadata(serverId, key);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGetDiagnosticsWhenResponseIs200() throws Exception {
|
||||||
|
|
||||||
|
String serverId = "123";
|
||||||
|
HttpRequest getDiagnostics = HttpRequest
|
||||||
|
.builder()
|
||||||
|
.method("GET")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/"+ serverId + "/diagnostics")
|
||||||
|
.addHeader("X-Auth-Token", authToken)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
HttpResponse serverDiagnosticsResponse = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
|
||||||
|
.payload(payloadFromResourceWithContentType("/server_diagnostics.json","application/json; charset=UTF-8")).build();
|
||||||
|
|
||||||
|
NovaApi apiWithNewServer = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
|
||||||
|
responseWithKeystoneAccess, getDiagnostics, serverDiagnosticsResponse);
|
||||||
|
assertEquals(apiWithNewServer.getServerApiForZone("az-1.region-a.geo-1").getDiagnostics(serverId),
|
||||||
|
new ParseServerDiagnostics().expected());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testGetDiagnosticsWhenResponseIs403Or404Or500() throws Exception {
|
||||||
|
|
||||||
|
String serverId = "123";
|
||||||
|
HttpRequest getDiagnostics = HttpRequest
|
||||||
|
.builder()
|
||||||
|
.method("GET")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/"+ serverId + "/diagnostics")
|
||||||
|
.addHeader("X-Auth-Token", authToken)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
for (int statusCode : ImmutableSet.of(403, 404, 500)) {
|
||||||
|
assertTrue(!requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess, getDiagnostics,
|
||||||
|
HttpResponse.builder().statusCode(statusCode).build()).getServerApiForZone("az-1.region-a.geo-1").getDiagnostics(serverId).isPresent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.jclouds.openstack.nova.v2_0.parse;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import org.jclouds.json.BaseItemParserTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Leander Beernaert
|
||||||
|
*/
|
||||||
|
public class ParseServerDiagnostics extends BaseItemParserTest<Optional<Map<String,String>>> {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Map<String,String>> expected() {
|
||||||
|
return Optional.<Map<String,String>>of(
|
||||||
|
new ImmutableMap.Builder<String,String>()
|
||||||
|
.put("vnet0_tx_errors", "0")
|
||||||
|
.put("vda_read","77364736")
|
||||||
|
.put("vda_write","415446016")
|
||||||
|
.put("vnet0_tx_packets","9701")
|
||||||
|
.put("vda_write_req","47278")
|
||||||
|
.put("cpu0_time","143150000000")
|
||||||
|
.put("vnet0_tx","1691221")
|
||||||
|
.put("vnet0_rx_drop","0")
|
||||||
|
.put("vda_errors","-1")
|
||||||
|
.put("vnet0_rx_errors","0")
|
||||||
|
.put("memory","524288")
|
||||||
|
.put("vnet0_rx_packets","11271")
|
||||||
|
.put("vda_read_req","9551")
|
||||||
|
.put("vnet0_rx","1805288")
|
||||||
|
.put("vnet0_tx_drop","0").build());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"vnet0_tx_errors": 0,
|
||||||
|
"vda_read": 77364736,
|
||||||
|
"vda_write": 415446016,
|
||||||
|
"vnet0_tx_packets": 9701,
|
||||||
|
"vda_write_req": 47278,
|
||||||
|
"cpu0_time": 143150000000,
|
||||||
|
"vnet0_tx": 1691221,
|
||||||
|
"vnet0_rx_drop": 0,
|
||||||
|
"vda_errors": -1,
|
||||||
|
"vnet0_rx_errors": 0,
|
||||||
|
"memory": 524288,
|
||||||
|
"vnet0_rx_packets": 11271,
|
||||||
|
"vda_read_req": 9551,
|
||||||
|
"vnet0_rx": 1805288,
|
||||||
|
"vnet0_tx_drop": 0
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds 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.rest.functions;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Leander Beernaert
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class ReturnAbsentOn403Or404Or500 implements Function<Exception, Object> {
|
||||||
|
|
||||||
|
|
||||||
|
public Object apply(Exception from) {
|
||||||
|
Boolean returnVal = returnValueOnCodeOrNull(from, true, Predicates.in(Ints.asList(403, 404, 500)));
|
||||||
|
if (returnVal != null)
|
||||||
|
return Optional.absent();
|
||||||
|
|
||||||
|
throw Throwables.propagate(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue