Implement the CloudStack 'alerts' API (available to the global administrator)

This commit is contained in:
Richard Downer 2011-12-05 14:36:57 +02:00
parent bdaebf8ce1
commit 3789aa3fc6
12 changed files with 576 additions and 51 deletions

View File

@ -19,6 +19,7 @@
package org.jclouds.cloudstack;
import org.jclouds.cloudstack.features.GlobalAccountAsyncClient;
import org.jclouds.cloudstack.features.GlobalAlertAsyncClient;
import org.jclouds.rest.annotations.Delegate;
/**
@ -34,10 +35,16 @@ import org.jclouds.rest.annotations.Delegate;
public interface CloudStackGlobalAsyncClient extends CloudStackDomainAsyncClient {
/**
* Provides synchronous access to Accounts
* Provides asynchronous access to Accounts
*/
@Delegate
@Override
GlobalAccountAsyncClient getAccountClient();
/**
* Provides asynchronous access to Alerts
*/
@Delegate
GlobalAlertAsyncClient getAlertClient();
}

View File

@ -21,6 +21,7 @@ package org.jclouds.cloudstack;
import java.util.concurrent.TimeUnit;
import org.jclouds.cloudstack.features.GlobalAccountClient;
import org.jclouds.cloudstack.features.GlobalAlertClient;
import org.jclouds.concurrent.Timeout;
import org.jclouds.rest.annotations.Delegate;
@ -43,4 +44,11 @@ public interface CloudStackGlobalClient extends CloudStackDomainClient {
@Delegate
@Override
GlobalAccountClient getAccountClient();
/**
* Provides synchronous access to Alerts
*/
@Delegate
GlobalAlertClient getAlertClient();
}

View File

@ -26,56 +26,7 @@ import org.jclouds.cloudstack.CloudStackDomainAsyncClient;
import org.jclouds.cloudstack.CloudStackDomainClient;
import org.jclouds.cloudstack.CloudStackGlobalAsyncClient;
import org.jclouds.cloudstack.CloudStackGlobalClient;
import org.jclouds.cloudstack.features.AccountAsyncClient;
import org.jclouds.cloudstack.features.AccountClient;
import org.jclouds.cloudstack.features.AddressAsyncClient;
import org.jclouds.cloudstack.features.AddressClient;
import org.jclouds.cloudstack.features.AsyncJobAsyncClient;
import org.jclouds.cloudstack.features.AsyncJobClient;
import org.jclouds.cloudstack.features.ConfigurationAsyncClient;
import org.jclouds.cloudstack.features.ConfigurationClient;
import org.jclouds.cloudstack.features.DomainAccountAsyncClient;
import org.jclouds.cloudstack.features.DomainAccountClient;
import org.jclouds.cloudstack.features.DomainLimitAsyncClient;
import org.jclouds.cloudstack.features.DomainLimitClient;
import org.jclouds.cloudstack.features.EventAsyncClient;
import org.jclouds.cloudstack.features.EventClient;
import org.jclouds.cloudstack.features.FirewallAsyncClient;
import org.jclouds.cloudstack.features.FirewallClient;
import org.jclouds.cloudstack.features.GlobalAccountAsyncClient;
import org.jclouds.cloudstack.features.GlobalAccountClient;
import org.jclouds.cloudstack.features.GuestOSAsyncClient;
import org.jclouds.cloudstack.features.GuestOSClient;
import org.jclouds.cloudstack.features.HypervisorAsyncClient;
import org.jclouds.cloudstack.features.HypervisorClient;
import org.jclouds.cloudstack.features.ISOAsyncClient;
import org.jclouds.cloudstack.features.ISOClient;
import org.jclouds.cloudstack.features.LimitAsyncClient;
import org.jclouds.cloudstack.features.LimitClient;
import org.jclouds.cloudstack.features.LoadBalancerAsyncClient;
import org.jclouds.cloudstack.features.LoadBalancerClient;
import org.jclouds.cloudstack.features.NATAsyncClient;
import org.jclouds.cloudstack.features.NATClient;
import org.jclouds.cloudstack.features.NetworkAsyncClient;
import org.jclouds.cloudstack.features.NetworkClient;
import org.jclouds.cloudstack.features.OfferingAsyncClient;
import org.jclouds.cloudstack.features.OfferingClient;
import org.jclouds.cloudstack.features.SSHKeyPairAsyncClient;
import org.jclouds.cloudstack.features.SSHKeyPairClient;
import org.jclouds.cloudstack.features.SecurityGroupAsyncClient;
import org.jclouds.cloudstack.features.SecurityGroupClient;
import org.jclouds.cloudstack.features.SnapshotAsyncClient;
import org.jclouds.cloudstack.features.SnapshotClient;
import org.jclouds.cloudstack.features.TemplateAsyncClient;
import org.jclouds.cloudstack.features.TemplateClient;
import org.jclouds.cloudstack.features.VMGroupAsyncClient;
import org.jclouds.cloudstack.features.VMGroupClient;
import org.jclouds.cloudstack.features.VirtualMachineAsyncClient;
import org.jclouds.cloudstack.features.VirtualMachineClient;
import org.jclouds.cloudstack.features.VolumeAsyncClient;
import org.jclouds.cloudstack.features.VolumeClient;
import org.jclouds.cloudstack.features.ZoneAsyncClient;
import org.jclouds.cloudstack.features.ZoneClient;
import org.jclouds.cloudstack.features.*;
import org.jclouds.cloudstack.handlers.CloudStackErrorHandler;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.RequiresHttp;
@ -128,6 +79,7 @@ public class CloudStackRestClientModule extends RestClientModule<CloudStackClien
.put(ISOClient.class, ISOAsyncClient.class)//
.put(VolumeClient.class, VolumeAsyncClient.class)//
.put(SnapshotClient.class, SnapshotAsyncClient.class)//
.put(GlobalAlertClient.class, GlobalAlertAsyncClient.class)//
.build();
@Override

View File

@ -0,0 +1,100 @@
/**
* 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.cloudstack.domain;
import java.util.Date;
/**
* Represents an alert issued by Cloudstack
*
* @author Richard Downer
*/
public class Alert implements Comparable<Alert> {
private long id;
private String description;
private Date sent;
private String type;
/* exists for the deserializer, only */
Alert() {
}
public Alert(long id, String description, Date sent, String type) {
this.id = id;
this.description = description;
this.sent = sent;
this.type = type;
}
public long getId() {
return id;
}
public String getDescription() {
return description;
}
public Date getSent() {
return sent;
}
public String getType() {
return type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Alert alert = (Alert) o;
if (id != alert.id) return false;
if (description != null ? !description.equals(alert.description) : alert.description != null) return false;
if (sent != null ? !sent.equals(alert.sent) : alert.sent != null) return false;
if (type != null ? !type.equals(alert.type) : alert.type != null) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (sent != null ? sent.hashCode() : 0);
result = 31 * result + (type != null ? type.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Alert{" +
"id=" + id +
", description='" + description + '\'' +
", sent=" + sent +
", type='" + type + '\'' +
'}';
}
@Override
public int compareTo(Alert other) {
return Long.valueOf(this.getId()).compareTo(other.getId());
}
}

View File

@ -0,0 +1,59 @@
/**
* 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.cloudstack.features;
import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.cloudstack.domain.Alert;
import org.jclouds.cloudstack.filters.QuerySigner;
import org.jclouds.cloudstack.options.ListAlertsOptions;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.core.MediaType;
import java.util.Set;
/**
* Provides asynchronous access to CloudStack Account features available to Global
* Admin users.
*
* @author Richard Downer
* @see <a href=
* "http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_Global_Admin.html"
* />
*/
@RequestFilters(QuerySigner.class)
@QueryParams(keys = "response", values = "json")
public interface GlobalAlertAsyncClient {
/**
* @see GlobalAlertClient#listAlerts(org.jclouds.cloudstack.options.ListAlertsOptions...)
*/
@GET
@QueryParams(keys = "command", values = "listAlerts")
@SelectJson("alert")
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Alert>> listAlerts(ListAlertsOptions...options);
}

View File

@ -0,0 +1,47 @@
/**
* 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.cloudstack.features;
import org.jclouds.cloudstack.domain.Alert;
import org.jclouds.cloudstack.options.ListAlertsOptions;
import org.jclouds.concurrent.Timeout;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Provides synchronous access to CloudStack Alerts features available to Global
* Admin users.
*
* @author Richard Downer
* @see <a href=
* "http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_Global_Admin.html"
* />
*/
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
public interface GlobalAlertClient {
/**
* List Alerts
*
* @return alert list or null if not found
*/
Set<Alert> listAlerts(ListAlertsOptions... options);
}

View File

@ -0,0 +1,68 @@
/**
* 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.cloudstack.options;
import com.google.common.collect.ImmutableSet;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Options to the listAlerts command.
*
* @author Richard Downer
*/
public class ListAlertsOptions extends BaseHttpRequestOptions {
public static final ListAlertsOptions NONE = new ListAlertsOptions();
public ListAlertsOptions id(long id) {
this.queryParameters.replaceValues("id", ImmutableSet.of(id + ""));
return this;
}
public ListAlertsOptions keyword(String keyword) {
this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword));
return this;
}
public ListAlertsOptions type(String type) {
this.queryParameters.replaceValues("type", ImmutableSet.of(type));
return this;
}
public static class Builder {
public static ListAlertsOptions id(long id) {
final ListAlertsOptions options = new ListAlertsOptions();
return options.id(id);
}
public static ListAlertsOptions keyword(String keyword) {
final ListAlertsOptions options = new ListAlertsOptions();
return options.keyword(keyword);
}
public static ListAlertsOptions type(String type) {
final ListAlertsOptions options = new ListAlertsOptions();
return options.type(type);
}
}
}

View File

@ -0,0 +1,82 @@
/**
* 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.cloudstack.features;
import com.google.inject.TypeLiteral;
import org.jclouds.cloudstack.options.ListAlertsOptions;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseFirstJsonValueNamed;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* Tests behavior of {@code GlobalAlertsAsyncClient}
*
* @author Richard Downer
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during
// surefire
@Test(groups = "unit", testName = "GlobalAlertAsyncClientTest")
public class GlobalAlertAsyncClientTest extends BaseCloudStackAsyncClientTest<GlobalAlertAsyncClient> {
public void testListAlerts() throws SecurityException, NoSuchMethodException, IOException {
Method method = GlobalAlertAsyncClient.class.getMethod("listAlerts", ListAlertsOptions[].class);
HttpRequest httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest,
"GET http://localhost:8080/client/api?response=json&command=listAlerts HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseFirstJsonValueNamed.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testListAlertsOptions() throws SecurityException, NoSuchMethodException, IOException {
Method method = GlobalAlertAsyncClient.class.getMethod("listAlerts", ListAlertsOptions[].class);
HttpRequest httpRequest = processor.createRequest(method, ListAlertsOptions.Builder.id(42).keyword("jclouds").type("TEMPLATE"));
assertRequestLineEquals(httpRequest,
"GET http://localhost:8080/client/api?response=json&command=listAlerts&id=42&keyword=jclouds&type=TEMPLATE HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ParseFirstJsonValueNamed.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<GlobalAlertAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<GlobalAlertAsyncClient>>() {
};
}
}

View File

@ -0,0 +1,55 @@
/**
* 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.cloudstack.features;
import org.jclouds.cloudstack.domain.Alert;
import org.jclouds.cloudstack.options.ListAlertsOptions;
import org.testng.annotations.Test;
import java.util.Set;
import static org.testng.Assert.*;
/**
* Tests behavior of {@code GlobalAlertsClient}
*
* @author Richard Downer
*/
@Test(groups = "live", singleThreaded = true, testName = "GlobalAlertClientLiveTest")
public class GlobalAlertClientLiveTest extends BaseCloudStackClientLiveTest {
@Test(groups = "live", enabled = true)
public void testListAlerts() throws Exception {
assertTrue(globalAdminEnabled, "Test cannot run without global admin identity and credentials");
final Set<Alert> response = globalAdminClient.getAlertClient().listAlerts(ListAlertsOptions.Builder.id(20));
assert null != response;
assertTrue(response.size() >= 0);
int count = 0;
for (Alert alert : response) {
assertNotNull(alert.getDescription());
assertNotSame(alert.getId(), 0);
assertNotNull(alert.getType());
assertNotNull(alert.getSent());
count++;
}
assertTrue(count > 0, "No alerts were returned, so I couldn't test");
}
}

View File

@ -0,0 +1,66 @@
/**
* 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.cloudstack.options;
import com.google.common.collect.ImmutableList;
import org.testng.annotations.Test;
import static org.jclouds.cloudstack.options.ListAlertsOptions.Builder.id;
import static org.jclouds.cloudstack.options.ListAlertsOptions.Builder.keyword;
import static org.jclouds.cloudstack.options.ListAlertsOptions.Builder.type;
import static org.testng.Assert.assertEquals;
/**
* Tests behavior of {@code ListAlertsOptions}
*
* @author Richard Downer
*/
@Test(groups = "unit")
public class ListAlertsOptionsTest {
public void testId() {
ListAlertsOptions options = new ListAlertsOptions().id(6);
assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
}
public void testIdStatic() {
ListAlertsOptions options = id(6);
assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("id"));
}
public void testKeyword() {
ListAlertsOptions options = new ListAlertsOptions().keyword("fred");
assertEquals(ImmutableList.of("fred"), options.buildQueryParameters().get("keyword"));
}
public void testKeywordStatic() {
ListAlertsOptions options = keyword("fred");
assertEquals(ImmutableList.of("fred"), options.buildQueryParameters().get("keyword"));
}
public void testType() {
ListAlertsOptions options = new ListAlertsOptions().type("42");
assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("type"));
}
public void testTypeStatic() {
ListAlertsOptions options = type("42");
assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("type"));
}
}

View File

@ -0,0 +1,80 @@
/**
* 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.cloudstack.parse;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.jclouds.cloudstack.config.CloudStackParserModule;
import org.jclouds.cloudstack.domain.Account;
import org.jclouds.cloudstack.domain.Account.State;
import org.jclouds.cloudstack.domain.Account.Type;
import org.jclouds.cloudstack.domain.Alert;
import org.jclouds.cloudstack.domain.User;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseSetParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import sun.util.resources.CalendarData;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
/**
*
* @author Richard Downer
*/
@Test(groups = "unit")
public class ListAlertsResponseTest extends BaseSetParserTest<Alert> {
@Override
protected Injector injector() {
return Guice.createInjector(new CloudStackParserModule(), new GsonModule() {
@Override
protected void configure() {
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure();
}
});
}
@Override
public String resource() {
return "/listalertsresponse.json";
}
@Override
@SelectJson("alert")
public Set<Alert> expected() {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, 2011);
c.set(Calendar.MONTH, Calendar.DECEMBER);
c.set(Calendar.DAY_OF_MONTH, 4);
c.set(Calendar.HOUR_OF_DAY, 12);
c.set(Calendar.MINUTE, 5);
c.set(Calendar.SECOND, 2);
return ImmutableSet.of(new Alert(20, "Failed to deploy Vm with Id: 52", c.getTime(), "7"));
}
}

View File

@ -0,0 +1 @@
{ "listalertsresponse" : { "count":1 ,"alert" : [ {"id":20,"type":7,"description":"Failed to deploy Vm with Id: 52","sent":"2011-12-04T10:05:02+0200"} ] } }