Implement create/list/deleteSnapshotPolicy in the Cloudstack API

This commit is contained in:
Richard Downer 2011-11-09 17:27:28 +02:00
parent 48f05f3aed
commit 61d9d1e5e6
8 changed files with 572 additions and 0 deletions

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.binders;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @author Richard Downer
*/
@Singleton
public class BindIdListToCommaDelimitedQueryParam implements Binder {
private final Provider<UriBuilder> uriBuilderProvider;
@Inject
public BindIdListToCommaDelimitedQueryParam(Provider<UriBuilder> uriBuilderProvider) {
this.uriBuilderProvider = checkNotNull(uriBuilderProvider, "uriBuilderProvider");
}
@SuppressWarnings("unchecked")
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(input instanceof Iterable<?>, "this binder is only valid for Iterables!");
Iterable<Long> numbers = (Iterable<Long>) checkNotNull(input, "list of Longs");
checkArgument(Iterables.size(numbers) > 0, "you must specify at least one element");
return ModifyRequest.addQueryParam(request, "ids", Joiner.on(',').join(numbers), uriBuilderProvider.get());
}
}

View File

@ -0,0 +1,58 @@
/**
* 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.binders;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import org.jclouds.cloudstack.domain.SnapshotPolicySchedule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import org.jclouds.rest.Binder;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
*
* @author Adrian Cole
*/
@Singleton
public class BindSnapshotPolicyScheduleToQueryParam implements Binder {
private final Provider<UriBuilder> uriBuilderProvider;
@Inject
public BindSnapshotPolicyScheduleToQueryParam(Provider<UriBuilder> uriBuilderProvider) {
this.uriBuilderProvider = checkNotNull(uriBuilderProvider, "uriBuilderProvider");
}
@SuppressWarnings("unchecked")
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
checkArgument(input instanceof SnapshotPolicySchedule, "this binder is only valid for SnapshotPolicySchedule");
SnapshotPolicySchedule schedule = (SnapshotPolicySchedule) input;
R modifiedResult = ModifyRequest.addQueryParam(request, "intervaltype", schedule.getIntervalType(), uriBuilderProvider.get());
modifiedResult = ModifyRequest.addQueryParam(modifiedResult, "schedule", schedule.getTime(), uriBuilderProvider.get());
return modifiedResult;
}
}

View File

@ -0,0 +1,169 @@
/**
* 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 com.google.gson.annotations.SerializedName;
/**
* @author Richard Downer
*/
public class SnapshotPolicy implements Comparable<SnapshotPolicy> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
private long id;
private Snapshot.SnapshotIntervalType intervalType;
private long numberToRetain;
private String schedule;
private String timezone;
private long volumeId;
/**
* @param id the ID of the snapshot policy
*/
public Builder id(long id) {
this.id = id;
return this;
}
/**
* @param intervalType valid types are hourly, daily, weekly, monthy, template, and none.
*/
public Builder intervalType(Snapshot.SnapshotIntervalType intervalType) {
this.intervalType = intervalType;
return this;
}
/**
* @param numberToRetain maximum number of snapshots retained
*/
public Builder numberToRetain(long numberToRetain) {
this.numberToRetain = numberToRetain;
return this;
}
/**
* @param schedule time the snapshot is scheduled to be taken.
*/
public Builder schedule(String schedule) {
this.schedule = schedule;
return this;
}
/**
* @param timezone the time zone of the snapshot policy
*/
public Builder timezone(String timezone) {
this.timezone = timezone;
return this;
}
/**
* @param volumeId ID of the disk volume
*/
public Builder volumeId(long volumeId) {
this.volumeId = volumeId;
return this;
}
}
private long id;
@SerializedName("intervaltype")
private Snapshot.SnapshotIntervalType intervalType;
@SerializedName("maxsnaps")
private long numberToRetain;
private String schedule;
private String timezone;
@SerializedName("volumeid")
private long volumeId;
/**
* present only for serializer
*/
SnapshotPolicy() {
}
/**
* @return the ID of the snapshot policy
*/
public long getId() {
return id;
}
/**
* @return valid types are hourly, daily, weekly, monthy, template, and none.
*/
public Snapshot.SnapshotIntervalType getIntervalType() {
return intervalType;
}
/**
* @return maximum number of snapshots retained
*/
public long getNumberToRetain() {
return numberToRetain;
}
/**
* @return time the snapshot is scheduled to be taken.
*/
public String getSchedule() {
return schedule;
}
/**
* @return the time zone of the snapshot policy
*/
public String getTimezone() {
return timezone;
}
/**
* @return ID of the disk volume
*/
public long getVolumeId() {
return volumeId;
}
@Override
public boolean equals(Object o) {
throw new RuntimeException("FIXME: Implement me");
}
@Override
public int hashCode() {
throw new RuntimeException("FIXME: Implement me");
}
@Override
public String toString() {
throw new RuntimeException("FIXME: Implement me");
}
@Override
public int compareTo(SnapshotPolicy other) {
throw new RuntimeException("FIXME: Implement me");
}
}

View File

@ -0,0 +1,41 @@
package org.jclouds.cloudstack.domain;
/**
* Describes the schedule of a snapshot policy.
*
* @author Richard Downer
*/
public class SnapshotPolicySchedule {
public static SnapshotPolicySchedule hourly(int minute) {
return new SnapshotPolicySchedule(Snapshot.SnapshotIntervalType.HOURLY, "FIXME");
}
public static SnapshotPolicySchedule daily(int hour, int minute) {
return new SnapshotPolicySchedule(Snapshot.SnapshotIntervalType.DAILY, "FIXME");
}
public static SnapshotPolicySchedule weekly(int day, int hour, int minute) {
return new SnapshotPolicySchedule(Snapshot.SnapshotIntervalType.WEEKLY, "FIXME");
}
public static SnapshotPolicySchedule monthly(int day, int hour, int minute) {
return new SnapshotPolicySchedule(Snapshot.SnapshotIntervalType.MONTHLY, String.format("%02d:%02d:%02d", minute, hour, day));
}
private Snapshot.SnapshotIntervalType intervalType;
private String time;
private SnapshotPolicySchedule(Snapshot.SnapshotIntervalType intervalType, String time) {
this.intervalType = intervalType;
this.time = time;
}
public Snapshot.SnapshotIntervalType getIntervalType() {
return intervalType;
}
public String getTime() {
return time;
}
}

View File

@ -19,11 +19,17 @@
package org.jclouds.cloudstack.features;
import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.cloudstack.binders.BindIdListToCommaDelimitedQueryParam;
import org.jclouds.cloudstack.binders.BindSnapshotPolicyScheduleToQueryParam;
import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.Snapshot;
import org.jclouds.cloudstack.domain.SnapshotPolicy;
import org.jclouds.cloudstack.domain.SnapshotPolicySchedule;
import org.jclouds.cloudstack.filters.QuerySigner;
import org.jclouds.cloudstack.options.CreateSnapshotOptions;
import org.jclouds.cloudstack.options.ListSnapshotPoliciesOptions;
import org.jclouds.cloudstack.options.ListSnapshotsOptions;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.OnlyElement;
import org.jclouds.rest.annotations.QueryParams;
@ -104,4 +110,57 @@ public interface SnapshotAsyncClient {
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteSnapshot(@QueryParam("id") long id);
/**
* Creates a snapshot policy for the account.
*
* @param schedule how to schedule snapshots
* @param numberToRetain maximum number of snapshots to retain
* @param timezone Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.
* @param volumeId the ID of the disk volume
* @return the newly-created snapshot policy
*/
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Unwrap
@QueryParams(keys = "command", values = "createSnapshotPolicy")
ListenableFuture<SnapshotPolicy> createSnapshotPolicy(@BinderParam(BindSnapshotPolicyScheduleToQueryParam.class) SnapshotPolicySchedule schedule, @QueryParam("maxsnaps") long numberToRetain, @QueryParam("timezone") String timezone, @QueryParam("volumeid") long volumeId);
/**
* Deletes a snapshot policy for the account.
*
* @param id The ID of the snapshot policy
* @return
*/
@GET
@Consumes(MediaType.APPLICATION_JSON)
@QueryParams(keys = "command", values = "deleteSnapshotPolicies")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteSnapshotPolicy(@QueryParam("id") long id);
/**
* Deletes snapshot policies for the account.
*
* @param id IDs of snapshot policies
* @return
*/
@GET
@Consumes(MediaType.APPLICATION_JSON)
@QueryParams(keys = "command", values = "deleteSnapshotPolicies")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteSnapshotPolicies(@BinderParam(BindIdListToCommaDelimitedQueryParam.class) Iterable<Long> id);
/**
* Lists snapshot policies.
*
* @param volumeId the ID of the disk volume
* @param options optional arguments
* @return the snapshot policies matching the query
*/
@GET
@Consumes(MediaType.APPLICATION_JSON)
@QueryParams(keys = "command", values = "listSnapshotPolicies")
@Unwrap
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<SnapshotPolicy>> listSnapshotPolicies(@QueryParam("volumeid") long volumeId, ListSnapshotPoliciesOptions... options);
}

View File

@ -20,10 +20,14 @@ package org.jclouds.cloudstack.features;
import org.jclouds.cloudstack.domain.AsyncCreateResponse;
import org.jclouds.cloudstack.domain.Snapshot;
import org.jclouds.cloudstack.domain.SnapshotPolicy;
import org.jclouds.cloudstack.domain.SnapshotPolicySchedule;
import org.jclouds.cloudstack.options.CreateSnapshotOptions;
import org.jclouds.cloudstack.options.ListSnapshotPoliciesOptions;
import org.jclouds.cloudstack.options.ListSnapshotsOptions;
import org.jclouds.concurrent.Timeout;
import javax.ws.rs.QueryParam;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -71,4 +75,40 @@ public interface SnapshotClient {
*/
void deleteSnapshot(long id);
/**
* Creates a snapshot policy for the account.
*
* @param schedule how to schedule snapshots
* @param numberToRetain maximum number of snapshots to retain
* @param timezone Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.
* @param volumeId the ID of the disk volume
* @return the newly-created snapshot policy
*/
SnapshotPolicy createSnapshotPolicy(SnapshotPolicySchedule schedule, long numberToRetain, String timezone, long volumeId);
/**
* Deletes a snapshot policy for the account.
*
* @param id The ID of the snapshot policy
* @return
*/
void deleteSnapshotPolicy(long id);
/**
* Deletes snapshot policies for the account.
*
* @param id IDs of snapshot policies
* @return
*/
void deleteSnapshotPolicies(Iterable<Long> id);
/**
* Lists snapshot policies.
*
* @param volumeId the ID of the disk volume
* @param options optional arguments
* @return the snapshot policies matching the query
*/
Set<SnapshotPolicy> listSnapshotPolicies(long volumeId, ListSnapshotPoliciesOptions... options);
}

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.ImmutableSet;
/**
* Options for the Snapshot listSnapshotPolicies method.
*
* @see org.jclouds.cloudstack.features.SnapshotClient#listSnapshotPolicies
* @see org.jclouds.cloudstack.features.SnapshotAsyncClient#listSnapshotPolicies
* @author Richard Downer
*/
public class ListSnapshotPoliciesOptions extends AccountInDomainOptions {
public static final ListSnapshotPoliciesOptions NONE = new ListSnapshotPoliciesOptions();
/**
* @param keyword List by keyword
*/
public ListSnapshotPoliciesOptions keyword(String keyword) {
this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword + ""));
return this;
}
public static class Builder {
/**
* @param account lists snapshot policies for the specified account.
*/
public static ListSnapshotPoliciesOptions accountInDomain(String account, long domainId) {
return (ListSnapshotPoliciesOptions) new ListSnapshotPoliciesOptions().accountInDomain(account, domainId);
}
/**
* @param domainId the domain ID.
*/
public static ListSnapshotPoliciesOptions domainId(long domainId) {
return (ListSnapshotPoliciesOptions) new ListSnapshotPoliciesOptions().domainId(domainId);
}
/**
* @param keyword List by keyword
*/
public static ListSnapshotPoliciesOptions keyword(String keyword) {
return new ListSnapshotPoliciesOptions().keyword(keyword);
}
}
}

View File

@ -19,9 +19,12 @@
package org.jclouds.cloudstack.features;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableSet;
import com.google.inject.TypeLiteral;
import org.jclouds.cloudstack.domain.Snapshot;
import org.jclouds.cloudstack.domain.SnapshotPolicySchedule;
import org.jclouds.cloudstack.options.CreateSnapshotOptions;
import org.jclouds.cloudstack.options.ListSnapshotPoliciesOptions;
import org.jclouds.cloudstack.options.ListSnapshotsOptions;
import org.jclouds.functions.IdentityFunction;
import org.jclouds.http.HttpRequest;
@ -144,6 +147,87 @@ public class SnapshotAsyncClientTest extends BaseCloudStackAsyncClientTest<Snaps
checkFilters(httpRequest);
}
public void testCreateSnapshotPolicy() throws NoSuchMethodException {
Method method = SnapshotAsyncClient.class.getMethod("createSnapshotPolicy", SnapshotPolicySchedule.class, long.class, String.class, long.class);
HttpRequest httpRequest = processor.createRequest(method, SnapshotPolicySchedule.monthly(5, 6, 7), 10, "UTC", 12);
assertRequestLineEquals(httpRequest,
"GET http://localhost:8080/client/api?response=json&command=createSnapshotPolicy&timezone=UTC&maxsnaps=10&volumeid=12&intervaltype=MONTHLY&schedule=07%3A06%3A05 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, UnwrapOnlyJsonValue.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
checkFilters(httpRequest);
}
public void testDeleteSnapshotPolicy() throws NoSuchMethodException {
Method method = SnapshotAsyncClient.class.getMethod("deleteSnapshotPolicy", long.class);
HttpRequest httpRequest = processor.createRequest(method, 7);
assertRequestLineEquals(httpRequest,
"GET http://localhost:8080/client/api?response=json&command=deleteSnapshotPolicies&id=7 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testDeleteSnapshotPolicies() throws NoSuchMethodException {
Method method = SnapshotAsyncClient.class.getMethod("deleteSnapshotPolicies", Iterable.class);
Iterable<Long> ids = ImmutableSet.of(3L, 5L, 7L);
HttpRequest httpRequest = processor.createRequest(method, ids);
assertRequestLineEquals(httpRequest,
"GET http://localhost:8080/client/api?response=json&command=deleteSnapshotPolicies&ids=3%2C5%2C7 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testListSnapshotPolicies() throws NoSuchMethodException {
Method method = SnapshotAsyncClient.class.getMethod("listSnapshotPolicies", long.class, ListSnapshotPoliciesOptions[].class);
HttpRequest httpRequest = processor.createRequest(method, 10);
assertRequestLineEquals(httpRequest,
"GET http://localhost:8080/client/api?response=json&command=listSnapshotPolicies&volumeid=10 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, UnwrapOnlyJsonValue.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
public void testListSnapshotPoliciesOptions() throws NoSuchMethodException {
Method method = SnapshotAsyncClient.class.getMethod("listSnapshotPolicies", long.class, ListSnapshotPoliciesOptions[].class);
HttpRequest httpRequest = processor.createRequest(method, 10, ListSnapshotPoliciesOptions.Builder.accountInDomain("fred", 4).keyword("bob"));
assertRequestLineEquals(httpRequest,
"GET http://localhost:8080/client/api?response=json&command=listSnapshotPolicies&volumeid=10&account=fred&domainid=4&keyword=bob HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
assertPayloadEquals(httpRequest, null, null, false);
assertResponseParserClassEquals(method, httpRequest, UnwrapOnlyJsonValue.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<SnapshotAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<SnapshotAsyncClient>>() {