diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/binders/BindIdListToCommaDelimitedQueryParam.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/binders/BindIdListToCommaDelimitedQueryParam.java new file mode 100644 index 0000000000..9e06beb905 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/binders/BindIdListToCommaDelimitedQueryParam.java @@ -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 uriBuilderProvider; + + @Inject + public BindIdListToCommaDelimitedQueryParam(Provider uriBuilderProvider) { + this.uriBuilderProvider = checkNotNull(uriBuilderProvider, "uriBuilderProvider"); + } + + @SuppressWarnings("unchecked") + @Override + public R bindToRequest(R request, Object input) { + checkArgument(input instanceof Iterable, "this binder is only valid for Iterables!"); + Iterable numbers = (Iterable) 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()); + } +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/binders/BindSnapshotPolicyScheduleToQueryParam.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/binders/BindSnapshotPolicyScheduleToQueryParam.java new file mode 100644 index 0000000000..15b7f5f5c1 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/binders/BindSnapshotPolicyScheduleToQueryParam.java @@ -0,0 +1,56 @@ +/** + * 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 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 uriBuilderProvider; + + @Inject + public BindSnapshotPolicyScheduleToQueryParam(Provider uriBuilderProvider) { + this.uriBuilderProvider = checkNotNull(uriBuilderProvider, "uriBuilderProvider"); + } + + @SuppressWarnings("unchecked") + @Override + public 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.getInterval(), uriBuilderProvider.get()); + modifiedResult = ModifyRequest.addQueryParam(modifiedResult, "schedule", schedule.getTime(), uriBuilderProvider.get()); + return modifiedResult; + } +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java new file mode 100644 index 0000000000..ae58c53412 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Snapshot.java @@ -0,0 +1,401 @@ +/** + * 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; + +import java.util.Date; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author Richard Downer + */ +public class Snapshot implements Comparable { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private long id; + private String account; + private Date created; + private String domain; + private long domainId; + private Interval interval; + private long jobId; + private String jobStatus; + private String name; + private Type snapshotType; + private State state; + private long volumeId; + private String volumeName; + private String volumeType; + + /** + * @param id ID of the snapshot + */ + public Builder id(long id) { + this.id = id; + return this; + } + + /** + * @param account the account associated with the snapshot + */ + public Builder account(String account) { + this.account = account; + return this; + } + + /** + * @param created the date the snapshot was created + */ + public Builder created(Date created) { + this.created = created; + return this; + } + + /** + * @param domain the domain name of the snapshot's account + */ + public Builder domain(String domain) { + this.domain = domain; + return this; + } + + /** + * @param domainId the domain ID of the snapshot's account + */ + public Builder domainId(long domainId) { + this.domainId = domainId; + return this; + } + + /** + * @param interval valid types are hourly, daily, weekly, monthy, template, and none. + */ + public Builder interval(Interval interval) { + this.interval = interval; + return this; + } + + /** + * @param jobId the job ID associated with the snapshot. This is only displayed if the snapshot listed is part of a currently running asynchronous job. + */ + public Builder jobId(long jobId) { + this.jobId = jobId; + return this; + } + + /** + * @param jobStatus the job status associated with the snapshot. This is only displayed if the snapshot listed is part of a currently running asynchronous job. + */ + public Builder jobStatus(String jobStatus) { + this.jobStatus = jobStatus; + return this; + } + + /** + * @param name name of the snapshot + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @param snapshotType the type of the snapshot + */ + public Builder snapshotType(Type snapshotType) { + this.snapshotType = snapshotType; + return this; + } + + /** + * @param state the state of the snapshot. BackedUp means that snapshot is ready to be used; Creating - the snapshot is being allocated on the primary storage; BackingUp - the snapshot is being backed up on secondary storage + */ + public Builder state(State state) { + this.state = state; + return this; + } + + /** + * @param volumeId ID of the disk volume + */ + public Builder volumeId(long volumeId) { + this.volumeId = volumeId; + return this; + } + + /** + * @param volumeName name of the disk volume + */ + public Builder volumeName(String volumeName) { + this.volumeName = volumeName; + return this; + } + + /** + * @param volumeType type of the disk volume + */ + public Builder volumeType(String volumeType) { + this.volumeType = volumeType; + return this; + } + + } + + public static enum State { + + BackedUp, Creating, BackingUp, UNRECOGNIZED; + + public static State fromValue(String type) { + try { + return valueOf(checkNotNull(type, "type")); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + } + + public static enum Type { + + MANUAL, RECURRING, UNRECOGNIZED; + + public static Type fromValue(String type) { + try { + return valueOf(checkNotNull(type, "type")); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + } + + public static enum Interval { + + HOURLY, DAILY, WEEKLY, MONTHLY, template, none, UNRECOGNIZED; + + public static Interval fromValue(String type) { + try { + return valueOf(checkNotNull(type, "type")); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + } + + private long id; + private String account; + private Date created; + private String domain; + @SerializedName("domainid") + private long domainId; + @SerializedName("intervaltype") + private Interval interval; + @SerializedName("jobid") + private long jobId; + @SerializedName("jobstatus") + private String jobStatus; + private String name; + @SerializedName("snapshottype") + private Type snapshotType; + private State state; + @SerializedName("volumeid") + private long volumeId; + @SerializedName("volumename") + private String volumeName; + @SerializedName("volumetype") + private String volumeType; // FIXME: replace this with a proper enumerated type (blocked until volume API implemented) + + /** + * present only for serializer + */ + Snapshot() { + } + + /** + * @return ID of the snapshot + */ + public long getId() { + return id; + } + + /** + * @return the account associated with the snapshot + */ + public String getAccount() { + return account; + } + + /** + * @return the date the snapshot was created + */ + public Date getCreated() { + return created; + } + + /** + * @return the domain name of the snapshot's account + */ + public String getDomain() { + return domain; + } + + /** + * @return the domain ID of the snapshot's account + */ + public long getDomainId() { + return domainId; + } + + /** + * @return valid types are hourly, daily, weekly, monthy, template, and none. + */ + public Interval getInterval() { + return interval; + } + + /** + * @return the job ID associated with the snapshot. This is only displayed if the snapshot listed is part of a currently running asynchronous job. + */ + public long getJobId() { + return jobId; + } + + /** + * @return the job status associated with the snapshot. This is only displayed if the snapshot listed is part of a currently running asynchronous job. + */ + public String getJobStatus() { + return jobStatus; + } + + /** + * @return name of the snapshot + */ + public String getName() { + return name; + } + + /** + * @return the type of the snapshot + */ + public Type getSnapshotType() { + return snapshotType; + } + + /** + * @return the state of the snapshot. BackedUp means that snapshot is ready to be used; Creating - the snapshot is being allocated on the primary storage; BackingUp - the snapshot is being backed up on secondary storage + */ + public State getState() { + return state; + } + + /** + * @return ID of the disk volume + */ + public long getVolumeId() { + return volumeId; + } + + /** + * @return name of the disk volume + */ + public String getVolumeName() { + return volumeName; + } + + /** + * @return type of the disk volume + */ + public String getVolumeType() { + return volumeType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Snapshot snapshot = (Snapshot) o; + + if (domainId != snapshot.domainId) return false; + if (id != snapshot.id) return false; + if (jobId != snapshot.jobId) return false; + if (volumeId != snapshot.volumeId) return false; + if (account != null ? !account.equals(snapshot.account) : snapshot.account != null) return false; + if (created != null ? !created.equals(snapshot.created) : snapshot.created != null) return false; + if (domain != null ? !domain.equals(snapshot.domain) : snapshot.domain != null) return false; + if (interval != snapshot.interval) return false; + if (jobStatus != null ? !jobStatus.equals(snapshot.jobStatus) : snapshot.jobStatus != null) return false; + if (name != null ? !name.equals(snapshot.name) : snapshot.name != null) return false; + if (snapshotType != snapshot.snapshotType) return false; + if (state != snapshot.state) return false; + if (volumeName != null ? !volumeName.equals(snapshot.volumeName) : snapshot.volumeName != null) return false; + if (volumeType != null ? !volumeType.equals(snapshot.volumeType) : snapshot.volumeType != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + (account != null ? account.hashCode() : 0); + result = 31 * result + (created != null ? created.hashCode() : 0); + result = 31 * result + (domain != null ? domain.hashCode() : 0); + result = 31 * result + (int) (domainId ^ (domainId >>> 32)); + result = 31 * result + (interval != null ? interval.hashCode() : 0); + result = 31 * result + (int) (jobId ^ (jobId >>> 32)); + result = 31 * result + (jobStatus != null ? jobStatus.hashCode() : 0); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (snapshotType != null ? snapshotType.hashCode() : 0); + result = 31 * result + (state != null ? state.hashCode() : 0); + result = 31 * result + (int) (volumeId ^ (volumeId >>> 32)); + result = 31 * result + (volumeName != null ? volumeName.hashCode() : 0); + result = 31 * result + (volumeType != null ? volumeType.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Snapshot[" + + "id=" + id + + ", account='" + account + '\'' + + ", created=" + created + + ", domain='" + domain + '\'' + + ", domainId=" + domainId + + ", interval=" + interval + + ", jobId=" + jobId + + ", jobStatus='" + jobStatus + '\'' + + ", name='" + name + '\'' + + ", snapshotType=" + snapshotType + + ", state=" + state + + ", volumeId=" + volumeId + + ", volumeName='" + volumeName + '\'' + + ", volumeType='" + volumeType + '\'' + + ']'; + } + + @Override + public int compareTo(Snapshot other) { + return new Long(this.id).compareTo(other.getId()); + } +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SnapshotPolicy.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SnapshotPolicy.java new file mode 100644 index 0000000000..a1aed92392 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SnapshotPolicy.java @@ -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 { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private long id; + private Snapshot.Interval interval; + 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 interval valid types are hourly, daily, weekly, monthy, template, and none. + */ + public Builder interval(Snapshot.Interval interval) { + this.interval = interval; + 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.Interval interval; + @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.Interval getInterval() { + return interval; + } + + /** + * @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"); + } + +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SnapshotPolicySchedule.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SnapshotPolicySchedule.java new file mode 100644 index 0000000000..1603446cc1 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/SnapshotPolicySchedule.java @@ -0,0 +1,44 @@ +/** + * 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; + +/** + * Describes the schedule of a snapshot policy. + * + * @see org.jclouds.cloudstack.util.SnapshotPolicySchedules + * @author Richard Downer + */ +public class SnapshotPolicySchedule { + + private Snapshot.Interval interval; + private String time; + + public SnapshotPolicySchedule(Snapshot.Interval interval, String time) { + this.interval = interval; + this.time = time; + } + + public Snapshot.Interval getInterval() { + return interval; + } + + public String getTime() { + return time; + } +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SnapshotAsyncClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SnapshotAsyncClient.java new file mode 100644 index 0000000000..7e57cacb99 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SnapshotAsyncClient.java @@ -0,0 +1,166 @@ +/** + * 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.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; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.Unwrap; +import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.Set; + +/** + * Provides synchronous access to CloudStack Snapshot features. + *

+ * + * @see SnapshotClient + * @see http://download.cloud.com/releases/2.2.0/api/TOC_User.html + * @author Richard Downer + */ +@RequestFilters(QuerySigner.class) +@QueryParams(keys = "response", values = "json") +public interface SnapshotAsyncClient { + + /** + * Creates an instant snapshot of a volume. + * + * @param volumeId The ID of the disk volume + * @param options optional arguments + * @return an asynchronous job structure + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @QueryParams(keys = "command", values = "createSnapshot") + @Unwrap + ListenableFuture createSnapshot(@QueryParam("volumeid") long volumeId, CreateSnapshotOptions... options); + + /** + * Lists all available snapshots for the account, matching the query described by the options. + * + * @param options optional arguments + * @return the snapshots matching the query + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @QueryParams(keys = "command", values = "listSnapshots") + @Unwrap + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listSnapshots(ListSnapshotsOptions... options); + + /** + * Gets a snapshot by its ID. + * + * @param id the snapshot ID + * @return the snapshot with the requested ID + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @QueryParams(keys = "command", values = "listSnapshots") + @SelectJson("snapshot") + @OnlyElement + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getSnapshot(@QueryParam("id") long id); + + /** + * Deletes a snapshot of a disk volume. + * + * @param id The ID of the snapshot + * @return an asynchronous job structure + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @QueryParams(keys = "command", values = "deleteSnapshot") + @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + ListenableFuture 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 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 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 deleteSnapshotPolicies(@BinderParam(BindIdListToCommaDelimitedQueryParam.class) Iterable 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> listSnapshotPolicies(@QueryParam("volumeid") long volumeId, ListSnapshotPoliciesOptions... options); + +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SnapshotClient.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SnapshotClient.java new file mode 100644 index 0000000000..f1274a2d60 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/SnapshotClient.java @@ -0,0 +1,114 @@ +/** + * 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.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; + +/** + * Provides synchronous access to CloudStack Snapshot features. + *

+ * + * @see SnapshotAsyncClient + * @see http://download.cloud.com/releases/2.2.0/api/TOC_User.html + * @author Richard Downer + */ +@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) +public interface SnapshotClient { + + /** + * Creates an instant snapshot of a volume. + * + * @param volumeId The ID of the disk volume + * @param options optional arguments + * @return an asynchronous job structure + */ + AsyncCreateResponse createSnapshot(long volumeId, CreateSnapshotOptions... options); + + /** + * Lists all available snapshots for the account, matching the query described by the options. + * + * @param options optional arguments + * @return the snapshots matching the query + */ + Set listSnapshots(ListSnapshotsOptions... options); + + /** + * Gets a snapshot by its ID. + * + * @param id the snapshot ID + * @return the snapshot with the requested ID + */ + Snapshot getSnapshot(long id); + + /** + * Deletes a snapshot of a disk volume. + * + * @param id The ID of the snapshot + * @return an asynchronous job structure + */ + 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 id); + + /** + * Lists snapshot policies. + * + * @param volumeId the ID of the disk volume + * @param options optional arguments + * @return the snapshot policies matching the query + */ + Set listSnapshotPolicies(long volumeId, ListSnapshotPoliciesOptions... options); + +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateSnapshotOptions.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateSnapshotOptions.java new file mode 100644 index 0000000000..40ddc098d7 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateSnapshotOptions.java @@ -0,0 +1,67 @@ +/** + * 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 createSnapshot method. + * + * @see org.jclouds.cloudstack.features.SnapshotClient#createSnapshot + * @see org.jclouds.cloudstack.features.SnapshotAsyncClient#createSnapshot + * @author Richard Downer + */ +public class CreateSnapshotOptions extends AccountInDomainOptions { + + public static final CreateSnapshotOptions NONE = new CreateSnapshotOptions(); + + /** + * @param policyId policy id of the snapshot, if this is null, then use MANUAL_POLICY. + */ + public CreateSnapshotOptions policyId(long policyId) { + this.queryParameters.replaceValues("policyid", ImmutableSet.of(policyId + "")); + return this; + } + + public static class Builder { + + /** + * @param account The account of the snapshot. + * @param domainId The domain ID of the snapshot. + */ + public static CreateSnapshotOptions accountInDomain(String account, long domainId) { + return (CreateSnapshotOptions) new CreateSnapshotOptions().accountInDomain(account, domainId); + } + + /** + * @param domainId The domain ID of the snapshot. + */ + public static CreateSnapshotOptions domainId(long domainId) { + return (CreateSnapshotOptions) new CreateSnapshotOptions().domainId(domainId); + } + + /** + * @param policyId policy id of the snapshot, if this is null, then use MANUAL_POLICY. + */ + public static CreateSnapshotOptions policyId(long policyId) { + return new CreateSnapshotOptions().policyId(policyId); + } + } + +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotPoliciesOptions.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotPoliciesOptions.java new file mode 100644 index 0000000000..790ba6f88d --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotPoliciesOptions.java @@ -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); + } + } + +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java new file mode 100644 index 0000000000..6a4ef54a2a --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListSnapshotsOptions.java @@ -0,0 +1,158 @@ +/** + * 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.cloudstack.domain.Snapshot; + +/** + * Options for the Snapshot listSnapshots method. + * + * @see org.jclouds.cloudstack.features.SnapshotClient#listSnapshots + * @see org.jclouds.cloudstack.features.SnapshotAsyncClient#listSnapshots + * @author Richard Downer + */ +public class ListSnapshotsOptions extends AccountInDomainOptions { + + public static final ListSnapshotsOptions NONE = new ListSnapshotsOptions(); + + /** + * @param id lists snapshot by snapshot ID + */ + public ListSnapshotsOptions id(long id) { + this.queryParameters.replaceValues("id", ImmutableSet.of(id + "")); + return this; + } + + /** + * @param interval valid values are HOURLY, DAILY, WEEKLY, and MONTHLY. + */ + public ListSnapshotsOptions interval(Snapshot.Interval interval) { + this.queryParameters.replaceValues("intervaltype", ImmutableSet.of(interval + "")); + return this; + } + + /** + * @param isRecursive defaults to false, but if true, lists all snapshots from the parent specified by the domain id till leaves. + */ + public ListSnapshotsOptions isRecursive(boolean isRecursive) { + this.queryParameters.replaceValues("isrecursive", ImmutableSet.of(isRecursive + "")); + return this; + } + + /** + * @param keyword List by keyword + */ + public ListSnapshotsOptions keyword(String keyword) { + this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword + "")); + return this; + } + + /** + * @param name lists snapshot by snapshot name + */ + public ListSnapshotsOptions name(String name) { + this.queryParameters.replaceValues("name", ImmutableSet.of(name + "")); + return this; + } + + /** + * @param snapshotType valid values are MANUAL or RECURRING. + */ + public ListSnapshotsOptions snapshotType(Snapshot.Type snapshotType) { + this.queryParameters.replaceValues("snapshottype", ImmutableSet.of(snapshotType + "")); + return this; + } + + /** + * @param volumeId the ID of the disk volume + */ + public ListSnapshotsOptions volumeId(long volumeId) { + this.queryParameters.replaceValues("volumeid", ImmutableSet.of(volumeId + "")); + return this; + } + + public static class Builder { + + /** + * @param account lists snapshot belonging to the specified account. + * @param domainId The domain ID. + */ + public static ListSnapshotsOptions accountInDomain(String account, long domainId) { + return (ListSnapshotsOptions) new ListSnapshotsOptions().accountInDomain(account, domainId); + } + + /** + * @param domainId the domain ID. + */ + public static ListSnapshotsOptions domainId(long domainId) { + return (ListSnapshotsOptions) new ListSnapshotsOptions().domainId(domainId); + } + + /** + * @param id lists snapshot by snapshot ID + */ + public static ListSnapshotsOptions id(long id) { + return new ListSnapshotsOptions().id(id); + } + + /** + * @param interval valid values are HOURLY, DAILY, WEEKLY, and MONTHLY. + */ + public static ListSnapshotsOptions interval(Snapshot.Interval interval) { + return new ListSnapshotsOptions().interval(interval); + } + + /** + * @param isRecursive defaults to false, but if true, lists all snapshots from the parent specified by the domain id till leaves. + */ + public static ListSnapshotsOptions isRecursive(boolean isRecursive) { + return new ListSnapshotsOptions().isRecursive(isRecursive); + } + + /** + * @param keyword List by keyword + */ + public static ListSnapshotsOptions keyword(String keyword) { + return new ListSnapshotsOptions().keyword(keyword); + } + + /** + * @param name lists snapshot by snapshot name + */ + public static ListSnapshotsOptions name(String name) { + return new ListSnapshotsOptions().name(name); + } + + /** + * @param snapshotType valid values are MANUAL or RECURRING. + */ + public static ListSnapshotsOptions snapshotType(Snapshot.Type snapshotType) { + return new ListSnapshotsOptions().snapshotType(snapshotType); + } + + /** + * @param volumeId the ID of the disk volume + */ + public static ListSnapshotsOptions volumeId(long volumeId) { + return new ListSnapshotsOptions().volumeId(volumeId); + } + } + +} diff --git a/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/util/SnapshotPolicySchedules.java b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/util/SnapshotPolicySchedules.java new file mode 100644 index 0000000000..44b6f240d7 --- /dev/null +++ b/sandbox-apis/cloudstack/src/main/java/org/jclouds/cloudstack/util/SnapshotPolicySchedules.java @@ -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.cloudstack.util; + +import org.jclouds.cloudstack.domain.Snapshot; +import org.jclouds.cloudstack.domain.SnapshotPolicySchedule; + +/** + * Methods to create SnapshotPolicySchedule objects in the format required by Cloudstack. + * + * @author Richard Downer + */ +public class SnapshotPolicySchedules { + public static SnapshotPolicySchedule hourly(int minute) { + return new SnapshotPolicySchedule(Snapshot.Interval.HOURLY, String.format("%02d", minute)); + } + + public static SnapshotPolicySchedule daily(int hour, int minute) { + return new SnapshotPolicySchedule(Snapshot.Interval.DAILY, String.format("%02d:%02d", minute, hour)); + } + + public static SnapshotPolicySchedule weekly(int day, int hour, int minute) { + return new SnapshotPolicySchedule(Snapshot.Interval.WEEKLY, String.format("%02d:%02d:%02d", minute, hour, day)); + } + + public static SnapshotPolicySchedule monthly(int day, int hour, int minute) { + return new SnapshotPolicySchedule(Snapshot.Interval.MONTHLY, String.format("%02d:%02d:%02d", minute, hour, day)); + } +} diff --git a/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SnapshotAsyncClientTest.java b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SnapshotAsyncClientTest.java new file mode 100644 index 0000000000..f50ad8c4e6 --- /dev/null +++ b/sandbox-apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/SnapshotAsyncClientTest.java @@ -0,0 +1,237 @@ +/** + * 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.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.cloudstack.util.SnapshotPolicySchedules; +import org.jclouds.functions.IdentityFunction; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.functions.ReleasePayloadAndReturn; +import org.jclouds.http.functions.UnwrapOnlyJsonValue; +import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions; +import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; +import org.jclouds.rest.internal.RestAnnotationProcessor; +import org.testng.annotations.Test; + +import java.lang.reflect.Method; + +/** + * Tests the behaviour of SnapshotAsyncClient. + * + * @see SnapshotAsyncClient + * @author Richard Downer + */ +// NOTE:without testName, this will not call @Before* and fail w/NPE during +// surefire +@Test(groups = "unit", testName = "SnapshotAsyncClientTest") +public class SnapshotAsyncClientTest extends BaseCloudStackAsyncClientTest { + + public void testCreateSnapshot() throws NoSuchMethodException { + Method method = SnapshotAsyncClient.class.getMethod("createSnapshot", long.class, CreateSnapshotOptions[].class); + HttpRequest httpRequest = processor.createRequest(method, 5); + + assertRequestLineEquals(httpRequest, + "GET http://localhost:8080/client/api?response=json&command=createSnapshot&volumeid=5 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 testCreateSnapshotOptions() throws NoSuchMethodException { + Method method = SnapshotAsyncClient.class.getMethod("createSnapshot", long.class, CreateSnapshotOptions[].class); + HttpRequest httpRequest = processor.createRequest(method, 5, CreateSnapshotOptions.Builder.accountInDomain("acc", 7).policyId(9)); + + assertRequestLineEquals(httpRequest, + "GET http://localhost:8080/client/api?response=json&command=createSnapshot&volumeid=5&account=acc&domainid=7&policyid=9 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 testListSnapshots() throws NoSuchMethodException { + Method method = SnapshotAsyncClient.class.getMethod("listSnapshots", ListSnapshotsOptions[].class); + HttpRequest httpRequest = processor.createRequest(method); + + assertRequestLineEquals(httpRequest, + "GET http://localhost:8080/client/api?response=json&command=listSnapshots 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 testGetSnapshot() throws NoSuchMethodException { + Method method = SnapshotAsyncClient.class.getMethod("getSnapshot", long.class); + HttpRequest httpRequest = processor.createRequest(method, 5); + + assertRequestLineEquals(httpRequest, + "GET http://localhost:8080/client/api?response=json&command=listSnapshots&id=5 HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, + Functions.compose(IdentityFunction.INSTANCE, IdentityFunction.INSTANCE).getClass()); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); + + checkFilters(httpRequest); + } + + public void testListSnapshotsOptions() throws NoSuchMethodException { + Method method = SnapshotAsyncClient.class.getMethod("listSnapshots", ListSnapshotsOptions[].class); + HttpRequest httpRequest = processor.createRequest(method, ListSnapshotsOptions.Builder.accountInDomain("acc", 7).id(5).interval(Snapshot.Interval.MONTHLY).isRecursive(true).keyword("fred").name("fred's snapshot").snapshotType(Snapshot.Type.RECURRING).volumeId(11)); + + assertRequestLineEquals(httpRequest, + "GET http://localhost:8080/client/api?response=json&command=listSnapshots&account=acc&domainid=7&id=5&intervaltype=MONTHLY&isrecursive=true&keyword=fred&name=fred%27s%20snapshot&snapshottype=RECURRING&volumeid=11 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 testDeleteSnapshot() throws NoSuchMethodException { + Method method = SnapshotAsyncClient.class.getMethod("deleteSnapshot", long.class); + HttpRequest httpRequest = processor.createRequest(method, 14); + + assertRequestLineEquals(httpRequest, + "GET http://localhost:8080/client/api?response=json&command=deleteSnapshot&id=14 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 testCreateSnapshotPolicy() throws NoSuchMethodException { + Method method = SnapshotAsyncClient.class.getMethod("createSnapshotPolicy", SnapshotPolicySchedule.class, long.class, String.class, long.class); + HttpRequest httpRequest = processor.createRequest(method, SnapshotPolicySchedules.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 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> createTypeLiteral() { + return new TypeLiteral>() { + }; + } +}