mirror of https://github.com/apache/jclouds.git
Merge branch 'master' of github.com:jclouds/jclouds into 1.5.x
* 'master' of github.com:jclouds/jclouds: minor volume test-related changes better exception message on key not found switched to buildView master is not accessible via getComputer Nova VolumeClient: adjusting attachment method names after review Issue 907: initial jenkins api Nova VolumeClient: improving javadocs Nova VolumeClient: improving javadocs Nova VolumeClient: improving javadocs Adding remaining VolumeClientExpectTest methods Adding CreateVolume and CreateSnapshot options and improving live tests accordingly Adding Volumes extension - first stage includes get/list volumes and list attachments
This commit is contained in:
commit
b6597630db
|
@ -28,6 +28,7 @@ import org.jclouds.openstack.nova.v1_1.extensions.HostAdministrationAsyncClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairAsyncClient;
|
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairAsyncClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupAsyncClient;
|
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupAsyncClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.extensions.SimpleTenantUsageAsyncClient;
|
import org.jclouds.openstack.nova.v1_1.extensions.SimpleTenantUsageAsyncClient;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.extensions.VolumeAsyncClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.features.ExtensionAsyncClient;
|
import org.jclouds.openstack.nova.v1_1.features.ExtensionAsyncClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.features.FlavorAsyncClient;
|
import org.jclouds.openstack.nova.v1_1.features.FlavorAsyncClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.features.ImageAsyncClient;
|
import org.jclouds.openstack.nova.v1_1.features.ImageAsyncClient;
|
||||||
|
@ -120,4 +121,10 @@ public interface NovaAsyncClient {
|
||||||
Optional<SimpleTenantUsageAsyncClient> getSimpleTenantUsageExtensionForZone(
|
Optional<SimpleTenantUsageAsyncClient> getSimpleTenantUsageExtensionForZone(
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous access to Volume features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
Optional<VolumeAsyncClient> getVolumeExtensionForZone(
|
||||||
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.jclouds.openstack.nova.v1_1.extensions.HostAdministrationClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
|
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
|
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.extensions.SimpleTenantUsageClient;
|
import org.jclouds.openstack.nova.v1_1.extensions.SimpleTenantUsageClient;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.extensions.VolumeClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.features.ExtensionClient;
|
import org.jclouds.openstack.nova.v1_1.features.ExtensionClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
|
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
|
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
|
||||||
|
@ -122,4 +123,12 @@ public interface NovaClient {
|
||||||
Optional<SimpleTenantUsageClient> getSimpleTenantUsageExtensionForZone(
|
Optional<SimpleTenantUsageClient> getSimpleTenantUsageExtensionForZone(
|
||||||
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Volume features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
Optional<VolumeClient> getVolumeExtensionForZone(
|
||||||
|
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
|
||||||
.put(KeyPairClient.class, KeyPairAsyncClient.class)
|
.put(KeyPairClient.class, KeyPairAsyncClient.class)
|
||||||
.put(HostAdministrationClient.class, HostAdministrationAsyncClient.class)
|
.put(HostAdministrationClient.class, HostAdministrationAsyncClient.class)
|
||||||
.put(SimpleTenantUsageClient.class, SimpleTenantUsageAsyncClient.class)
|
.put(SimpleTenantUsageClient.class, SimpleTenantUsageAsyncClient.class)
|
||||||
|
.put(VolumeClient.class, VolumeAsyncClient.class)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public NovaRestClientModule() {
|
public NovaRestClientModule() {
|
||||||
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.base.CaseFormat;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Objects.ToStringHelper;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Openstack Nova Volume
|
||||||
|
*/
|
||||||
|
public class Volume {
|
||||||
|
|
||||||
|
public static enum Status {
|
||||||
|
CREATING, AVAILABLE, IN_USE, DELETING, ERROR, UNRECOGNIZED;
|
||||||
|
public String value() {
|
||||||
|
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Status fromValue(String status) {
|
||||||
|
try {
|
||||||
|
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(status, "status")));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return UNRECOGNIZED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder<?> builder() {
|
||||||
|
return new ConcreteBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder<?> toBuilder() {
|
||||||
|
return new ConcreteBuilder().fromVolume(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class Builder<T extends Builder<T>> {
|
||||||
|
protected abstract T self();
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private Status status;
|
||||||
|
private int size;
|
||||||
|
private String zone;
|
||||||
|
private Date created;
|
||||||
|
private Set<VolumeAttachment> attachments = Sets.newLinkedHashSet();
|
||||||
|
private String volumeType;
|
||||||
|
private String snapshotId;
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private Map<String, String> metadata = Maps.newHashMap();
|
||||||
|
|
||||||
|
/** @see Volume#getId() */
|
||||||
|
public T id(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getStatus() */
|
||||||
|
public T status(Status status) {
|
||||||
|
this.status = status;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getSize() */
|
||||||
|
public T size(int size) {
|
||||||
|
this.size = size;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getZone() */
|
||||||
|
public T zone(String zone) {
|
||||||
|
this.zone = zone;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getCreated() */
|
||||||
|
public T created(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getAttachments() */
|
||||||
|
public T attachments(Set<VolumeAttachment> attachments) {
|
||||||
|
this.attachments = attachments;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getVolumeType() */
|
||||||
|
public T volumeType(String volumeType) {
|
||||||
|
this.volumeType = volumeType;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getSnapshotId() */
|
||||||
|
public T snapshotId(String snapshotId) {
|
||||||
|
this.snapshotId = snapshotId;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getMetadata() */
|
||||||
|
public T metadata(Map<String, String> metadata) {
|
||||||
|
this.metadata = metadata;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getName() */
|
||||||
|
public T name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see Volume#getDescription() */
|
||||||
|
public T description(String description) {
|
||||||
|
this.description = description;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Volume build() {
|
||||||
|
return new Volume(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T fromVolume(Volume in) {
|
||||||
|
return this
|
||||||
|
.id(in.getId())
|
||||||
|
.status(in.getStatus())
|
||||||
|
.size(in.getSize())
|
||||||
|
.zone(in.getZone())
|
||||||
|
.created(in.getCreated())
|
||||||
|
.attachments(in.getAttachments())
|
||||||
|
.volumeType(in.getVolumeType())
|
||||||
|
.snapshotId(in.getSnapshotId())
|
||||||
|
.metadata(in.getMetadata())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||||
|
@Override
|
||||||
|
protected ConcreteBuilder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final Status status;
|
||||||
|
private final int size;
|
||||||
|
@SerializedName(value="availabilityZone")
|
||||||
|
private final String zone;
|
||||||
|
@SerializedName(value="createdAt")
|
||||||
|
private final Date created;
|
||||||
|
private final Set<VolumeAttachment> attachments;
|
||||||
|
private final String volumeType;
|
||||||
|
private final String snapshotId;
|
||||||
|
@SerializedName(value="displayName")
|
||||||
|
private final String name;
|
||||||
|
@SerializedName(value="displayDescription")
|
||||||
|
private final String description;
|
||||||
|
private final Map<String, String> metadata;
|
||||||
|
|
||||||
|
protected Volume(Builder<?> builder) {
|
||||||
|
this.id = builder.id;
|
||||||
|
this.status = builder.status;
|
||||||
|
this.size = builder.size;
|
||||||
|
this.zone = builder.zone;
|
||||||
|
this.created = builder.created;
|
||||||
|
this.attachments = ImmutableSet.copyOf(checkNotNull(builder.attachments, "attachments"));
|
||||||
|
this.volumeType = builder.volumeType;
|
||||||
|
this.snapshotId = builder.snapshotId;
|
||||||
|
this.name = builder.name;
|
||||||
|
this.description = builder.description;
|
||||||
|
this.metadata = ImmutableMap.copyOf(checkNotNull(builder.metadata, "metadata"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id of this volume
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the status of this volume
|
||||||
|
*/
|
||||||
|
public Status getStatus() {
|
||||||
|
return this.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the size in GB of this volume
|
||||||
|
*/
|
||||||
|
public int getSize() {
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the availabilityZone containing this volume
|
||||||
|
*/
|
||||||
|
public String getZone() {
|
||||||
|
return this.zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the time this volume was created
|
||||||
|
*/
|
||||||
|
public Date getCreated() {
|
||||||
|
return this.created;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the set of attachments (to Servers)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Set<VolumeAttachment> getAttachments() {
|
||||||
|
return Collections.unmodifiableSet(this.attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the type of this volume
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getVolumeType() {
|
||||||
|
return this.volumeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getSnapshotId() {
|
||||||
|
return this.snapshotId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of this volume - as displayed in the openstack console
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the description of this volume - as displayed in the openstack console
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Map<String, String> getMetadata() {
|
||||||
|
return Collections.unmodifiableMap(this.metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keeping fields short in eq/hashCode so that minor state differences don't affect collection membership
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(id, zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null || getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Volume that = Volume.class.cast(obj);
|
||||||
|
return Objects.equal(this.id, that.id) && Objects.equal(this.zone, that.zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToStringHelper string() {
|
||||||
|
return Objects.toStringHelper("")
|
||||||
|
.add("id", id)
|
||||||
|
.add("status", status)
|
||||||
|
.add("size", size)
|
||||||
|
.add("zone", zone)
|
||||||
|
.add("created", created)
|
||||||
|
.add("attachments", attachments)
|
||||||
|
.add("volumeType", volumeType)
|
||||||
|
.add("snapshotId", snapshotId)
|
||||||
|
.add("name", name)
|
||||||
|
.add("description", description)
|
||||||
|
.add("metadata", metadata)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return string().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Objects.ToStringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Openstack Nova Volume Attachment (describes how Volumes are attached to Servers)
|
||||||
|
*/
|
||||||
|
public class VolumeAttachment {
|
||||||
|
|
||||||
|
public static Builder<?> builder() {
|
||||||
|
return new ConcreteBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder<?> toBuilder() {
|
||||||
|
return new ConcreteBuilder().fromAttachment(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class Builder<T extends Builder<T>> {
|
||||||
|
protected abstract T self();
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String volumeId;
|
||||||
|
private String serverId;
|
||||||
|
private String device;
|
||||||
|
|
||||||
|
/** @see VolumeAttachment#getId() */
|
||||||
|
public T id(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeAttachment#getVolumeId() */
|
||||||
|
public T volumeId(String volumeId) {
|
||||||
|
this.volumeId = volumeId;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeAttachment#getServerId() */
|
||||||
|
public T serverId(String serverId) {
|
||||||
|
this.serverId = serverId;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeAttachment#getDevice() */
|
||||||
|
public T device(String device) {
|
||||||
|
this.device = device;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeAttachment build() {
|
||||||
|
return new VolumeAttachment(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T fromAttachment(VolumeAttachment in) {
|
||||||
|
return this
|
||||||
|
.id(in.getId())
|
||||||
|
.volumeId(in.getVolumeId())
|
||||||
|
.serverId(in.getServerId())
|
||||||
|
.device(in.getDevice())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||||
|
@Override
|
||||||
|
protected ConcreteBuilder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String volumeId;
|
||||||
|
private final String serverId;
|
||||||
|
private final String device;
|
||||||
|
|
||||||
|
protected VolumeAttachment(Builder<?> builder) {
|
||||||
|
this.id = checkNotNull(builder.id, "id");
|
||||||
|
this.volumeId = checkNotNull(builder.volumeId, "volumeId");
|
||||||
|
this.serverId = builder.serverId;
|
||||||
|
this.device = builder.device;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the attachment id (typically the same as #getVolumeId())
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id of the volume attached
|
||||||
|
*/
|
||||||
|
public String getVolumeId() {
|
||||||
|
return this.volumeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id of the server the volume is attached to
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getServerId() {
|
||||||
|
return this.serverId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the device name (e.g. "/dev/vdc")
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getDevice() {
|
||||||
|
return this.device;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(id, volumeId, serverId, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null || getClass() != obj.getClass()) return false;
|
||||||
|
VolumeAttachment that = VolumeAttachment.class.cast(obj);
|
||||||
|
return Objects.equal(this.id, that.id)
|
||||||
|
&& Objects.equal(this.volumeId, that.volumeId)
|
||||||
|
&& Objects.equal(this.serverId, that.serverId)
|
||||||
|
&& Objects.equal(this.device, that.device)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToStringHelper string() {
|
||||||
|
return Objects.toStringHelper("")
|
||||||
|
.add("id", id)
|
||||||
|
.add("volumeId", volumeId)
|
||||||
|
.add("serverId", serverId)
|
||||||
|
.add("device", device)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return string().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Objects.ToStringHelper;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Openstack Nova Volume Snapshot
|
||||||
|
*/
|
||||||
|
public class VolumeSnapshot {
|
||||||
|
|
||||||
|
public static Builder<?> builder() {
|
||||||
|
return new ConcreteBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder<?> toBuilder() {
|
||||||
|
return new ConcreteBuilder().fromSnapshot(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class Builder<T extends Builder<T>> {
|
||||||
|
protected abstract T self();
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String volumeId;
|
||||||
|
private Volume.Status status;
|
||||||
|
private int size;
|
||||||
|
private Date created;
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/** @see VolumeSnapshot#getId() */
|
||||||
|
public T id(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeSnapshot#getVolumeId() */
|
||||||
|
public T volumeId(String volumeId) {
|
||||||
|
this.volumeId = volumeId;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeSnapshot#getStatus() */
|
||||||
|
public T status(Volume.Status status) {
|
||||||
|
this.status = status;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeSnapshot#getSize() */
|
||||||
|
public T size(int size) {
|
||||||
|
this.size = size;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeSnapshot#getCreated() */
|
||||||
|
public T created(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeSnapshot#getName() */
|
||||||
|
public T name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see VolumeSnapshot#getDescription() */
|
||||||
|
public T description(String description) {
|
||||||
|
this.description = description;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VolumeSnapshot build() {
|
||||||
|
return new VolumeSnapshot(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T fromSnapshot(VolumeSnapshot in) {
|
||||||
|
return this
|
||||||
|
.id(in.getId())
|
||||||
|
.volumeId(in.getVolumeId())
|
||||||
|
.status(in.getStatus())
|
||||||
|
.size(in.getSize())
|
||||||
|
.created(in.getCreated())
|
||||||
|
.name(in.getName())
|
||||||
|
.description(in.getDescription())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||||
|
@Override
|
||||||
|
protected ConcreteBuilder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String volumeId;
|
||||||
|
private final Volume.Status status;
|
||||||
|
private final int size;
|
||||||
|
@SerializedName(value="createdAt")
|
||||||
|
private final Date created;
|
||||||
|
@SerializedName(value="displayName")
|
||||||
|
private final String name;
|
||||||
|
@SerializedName(value="displayDescription")
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
protected VolumeSnapshot(Builder<?> builder) {
|
||||||
|
this.id = checkNotNull(builder.id, "id");
|
||||||
|
this.volumeId = checkNotNull(builder.volumeId, "volumeId");
|
||||||
|
this.status = checkNotNull(builder.status, "status");
|
||||||
|
this.size = builder.size;
|
||||||
|
this.created = builder.created;
|
||||||
|
this.name = builder.name;
|
||||||
|
this.description = builder.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id of this snapshot
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id of the Volume this snapshot was taken from
|
||||||
|
*/
|
||||||
|
public String getVolumeId() {
|
||||||
|
return this.volumeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the status of this snapshot
|
||||||
|
*/
|
||||||
|
public Volume.Status getStatus() {
|
||||||
|
return this.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the size in GB of the volume this snapshot was taken from
|
||||||
|
*/
|
||||||
|
public int getSize() {
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the data the snapshot was taken
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Date getCreated() {
|
||||||
|
return this.created;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of this snapshot - as displayed in the openstack console
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the description of this snapshot - as displayed in the openstack console
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(id, volumeId, status, size, created, name, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null || getClass() != obj.getClass()) return false;
|
||||||
|
VolumeSnapshot that = VolumeSnapshot.class.cast(obj);
|
||||||
|
return Objects.equal(this.id, that.id)
|
||||||
|
&& Objects.equal(this.volumeId, that.volumeId)
|
||||||
|
&& Objects.equal(this.status, that.status)
|
||||||
|
&& Objects.equal(this.size, that.size)
|
||||||
|
&& Objects.equal(this.created, that.created)
|
||||||
|
&& Objects.equal(this.name, that.name)
|
||||||
|
&& Objects.equal(this.description, that.description)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToStringHelper string() {
|
||||||
|
return Objects.toStringHelper("")
|
||||||
|
.add("id", id)
|
||||||
|
.add("volumeId", volumeId)
|
||||||
|
.add("status", status)
|
||||||
|
.add("size", size)
|
||||||
|
.add("created", created)
|
||||||
|
.add("name", name)
|
||||||
|
.add("description", description)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return string().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,234 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.extensions;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeSnapshot;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.Volume;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeSnapshotOptions;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeOptions;
|
||||||
|
import org.jclouds.openstack.services.Extension;
|
||||||
|
import org.jclouds.openstack.services.ServiceType;
|
||||||
|
import org.jclouds.rest.annotations.ExceptionParser;
|
||||||
|
import org.jclouds.rest.annotations.MapBinder;
|
||||||
|
import org.jclouds.rest.annotations.Payload;
|
||||||
|
import org.jclouds.rest.annotations.PayloadParam;
|
||||||
|
import org.jclouds.rest.annotations.RequestFilters;
|
||||||
|
import org.jclouds.rest.annotations.SelectJson;
|
||||||
|
import org.jclouds.rest.annotations.SkipEncoding;
|
||||||
|
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
|
||||||
|
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
|
||||||
|
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Volumes.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @see org.jclouds.openstack.nova.v1_1.extensions.VolumeAsyncClient
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUMES)
|
||||||
|
@SkipEncoding({'/', '='})
|
||||||
|
@RequestFilters(AuthenticateRequest.class)
|
||||||
|
public interface VolumeAsyncClient {
|
||||||
|
/**
|
||||||
|
* Returns a summary list of volumes.
|
||||||
|
*
|
||||||
|
* @return the list of volumes
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/os-volumes")
|
||||||
|
@SelectJson("volumes")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Set<Volume>> listVolumes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a detailed list of volumes.
|
||||||
|
*
|
||||||
|
* @return the list of volumes.
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/os-volumes/detail")
|
||||||
|
@SelectJson("volumes")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Set<Volume>> listVolumesInDetail();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data about the given volume.
|
||||||
|
*
|
||||||
|
* @return details of a specific volume.
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/os-volumes/{id}")
|
||||||
|
@SelectJson("volume")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Volume> getVolume(@PathParam("id") String volumeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new volume
|
||||||
|
*
|
||||||
|
* @return the new Snapshot
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("/os-volumes")
|
||||||
|
@SelectJson("volume")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@MapBinder(CreateVolumeOptions.class)
|
||||||
|
ListenableFuture<Volume> createVolume(@PayloadParam("size") int sizeGB, CreateVolumeOptions... options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a volume.
|
||||||
|
*
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@Path("/os-volumes/{id}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Boolean> deleteVolume(@PathParam("id") String volumeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List volume attachments for a given instance.
|
||||||
|
*
|
||||||
|
* @return all Floating IPs
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments")
|
||||||
|
@SelectJson("volumeAttachments")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Set<VolumeAttachment>> listAttachmentsOnServer(@PathParam("server_id") String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific attached volume.
|
||||||
|
*
|
||||||
|
* @return data about the given volume attachment.
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
||||||
|
@SelectJson("volumeAttachment")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<VolumeAttachment> getAttachmentForVolumeOnServer(@PathParam("id") String volumeId,
|
||||||
|
@PathParam("server_id") String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a volume to an instance
|
||||||
|
*
|
||||||
|
* @return the new Attachment
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments")
|
||||||
|
@SelectJson("volumeAttachment")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Payload("%7B\"volumeAttachment\":%7B\"volumeId\":\"{id}\",\"device\":\"{device}\"%7D%7D")
|
||||||
|
ListenableFuture<VolumeAttachment> attachVolumeToServerAsDevice(@PayloadParam("id") String volumeId,
|
||||||
|
@PathParam("server_id") String serverId, @PayloadParam("device") String device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach a Volume from an instance.
|
||||||
|
*
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@Path("/servers/{server_id}/os-volume_attachments/{id}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Boolean> detachVolumeFromServer(@PathParam("id") String volumeId, @PathParam("server_id") String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a summary list of snapshots.
|
||||||
|
*
|
||||||
|
* @return the list of snapshots
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/os-snapshots")
|
||||||
|
@SelectJson("snapshots")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Set<VolumeSnapshot>> listSnapshots();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a summary list of snapshots.
|
||||||
|
*
|
||||||
|
* @return the list of snapshots
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/os-snapshots/detail")
|
||||||
|
@SelectJson("snapshots")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Set<VolumeSnapshot>> listSnapshotsInDetail();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data about the given snapshot.
|
||||||
|
*
|
||||||
|
* @return details of a specific snapshot.
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/os-snapshots/{id}")
|
||||||
|
@SelectJson("snapshot")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<VolumeSnapshot> getSnapshot(@PathParam("id") String snapshotId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Snapshot
|
||||||
|
*
|
||||||
|
* @return the new Snapshot
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("/os-snapshots")
|
||||||
|
@SelectJson("snapshot")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@MapBinder(CreateVolumeSnapshotOptions.class)
|
||||||
|
ListenableFuture<VolumeSnapshot> createSnapshot(@PayloadParam("volume_id") String volumeId, CreateVolumeSnapshotOptions... options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a snapshot.
|
||||||
|
*
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@Path("/os-snapshots/{id}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Boolean> deleteSnapshot(@PathParam("id") String snapshotId);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.extensions;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeSnapshot;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.Volume;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeSnapshotOptions;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeOptions;
|
||||||
|
import org.jclouds.openstack.services.Extension;
|
||||||
|
import org.jclouds.openstack.services.ServiceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Volumes.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @see org.jclouds.openstack.nova.v1_1.extensions.VolumeAsyncClient
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUMES)
|
||||||
|
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||||
|
public interface VolumeClient {
|
||||||
|
/**
|
||||||
|
* Returns a summary list of snapshots.
|
||||||
|
*
|
||||||
|
* @return the list of snapshots
|
||||||
|
*/
|
||||||
|
Set<Volume> listVolumes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a detailed list of volumes.
|
||||||
|
*
|
||||||
|
* @return the list of volumes.
|
||||||
|
*/
|
||||||
|
Set<Volume> listVolumesInDetail();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data about the given volume.
|
||||||
|
*
|
||||||
|
* @return details of a specific snapshot.
|
||||||
|
*/
|
||||||
|
Volume getVolume(String volumeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Snapshot
|
||||||
|
*
|
||||||
|
* @return the new Snapshot
|
||||||
|
*/
|
||||||
|
Volume createVolume(int sizeGB, CreateVolumeOptions... options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a snapshot.
|
||||||
|
*
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
Boolean deleteVolume(String volumeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List volume attachments for a given instance.
|
||||||
|
*
|
||||||
|
* @return all Floating IPs
|
||||||
|
*/
|
||||||
|
Set<VolumeAttachment> listAttachmentsOnServer(String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a specific attached volume.
|
||||||
|
*
|
||||||
|
* @return data about the given volume attachment.
|
||||||
|
*/
|
||||||
|
VolumeAttachment getAttachmentForVolumeOnServer(String volumeId, String serverId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a volume to an instance
|
||||||
|
*
|
||||||
|
* @return data about the new volume attachment
|
||||||
|
*/
|
||||||
|
VolumeAttachment attachVolumeToServerAsDevice(String volumeId, String serverId, String device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach a Volume from an instance.
|
||||||
|
*
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
Boolean detachVolumeFromServer(String server_id, String volumeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a summary list of snapshots.
|
||||||
|
*
|
||||||
|
* @return the list of snapshots
|
||||||
|
*/
|
||||||
|
Set<VolumeSnapshot> listSnapshots();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a summary list of snapshots.
|
||||||
|
*
|
||||||
|
* @return the list of snapshots
|
||||||
|
*/
|
||||||
|
Set<VolumeSnapshot> listSnapshotsInDetail();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data about the given snapshot.
|
||||||
|
*
|
||||||
|
* @return details of a specific snapshot.
|
||||||
|
*/
|
||||||
|
VolumeSnapshot getSnapshot(String snapshotId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Snapshot
|
||||||
|
*
|
||||||
|
* @return the new Snapshot
|
||||||
|
*/
|
||||||
|
VolumeSnapshot createSnapshot(String volumeId, CreateVolumeSnapshotOptions... options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a snapshot.
|
||||||
|
*
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
Boolean deleteSnapshot(String snapshotId);
|
||||||
|
|
||||||
|
}
|
|
@ -66,6 +66,8 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
|
||||||
URI.create("http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1"))
|
URI.create("http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1"))
|
||||||
.put(URI.create(ExtensionNamespaces.HOSTS),
|
.put(URI.create(ExtensionNamespaces.HOSTS),
|
||||||
URI.create("http://docs.openstack.org/compute/ext/hosts/api/v1.1"))
|
URI.create("http://docs.openstack.org/compute/ext/hosts/api/v1.1"))
|
||||||
|
.put(URI.create(ExtensionNamespaces.VOLUMES),
|
||||||
|
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|
|
@ -67,6 +67,9 @@ public class NovaErrorHandler implements HttpErrorHandler {
|
||||||
exception = new ResourceNotFoundException(message, exception);
|
exception = new ResourceNotFoundException(message, exception);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 413:
|
||||||
|
exception = new InsufficientResourcesException(message, exception);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
command.setException(exception);
|
command.setException(exception);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.options;
|
||||||
|
|
||||||
|
import static com.google.common.base.Objects.equal;
|
||||||
|
import static com.google.common.base.Objects.toStringHelper;
|
||||||
|
import static com.google.common.base.Preconditions.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.jclouds.encryption.internal.Base64;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
|
||||||
|
import org.jclouds.rest.MapBinder;
|
||||||
|
import org.jclouds.rest.binders.BindToJsonPayload;
|
||||||
|
import org.jclouds.util.Preconditions2;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Objects.ToStringHelper;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
public class CreateVolumeOptions implements MapBinder {
|
||||||
|
public static final CreateVolumeOptions NONE = new CreateVolumeOptions();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BindToJsonPayload jsonBinder;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private String volumeType;
|
||||||
|
private String availabilityZone;
|
||||||
|
private String snapshotId;
|
||||||
|
private Map<String, String> metadata = ImmutableMap.of();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
|
||||||
|
Map<String, Object> image = Maps.newHashMap();
|
||||||
|
image.putAll(postParams);
|
||||||
|
if (name != null)
|
||||||
|
image.put("display_name", name);
|
||||||
|
if (description != null)
|
||||||
|
image.put("display_description", description);
|
||||||
|
if (!metadata.isEmpty())
|
||||||
|
image.put("metadata", metadata);
|
||||||
|
return jsonBinder.bindToRequest(request, ImmutableMap.of("volume", image));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
|
||||||
|
throw new IllegalStateException("CreateVolume is a POST operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(object instanceof CreateVolumeOptions)) return false;
|
||||||
|
final CreateVolumeOptions other = CreateVolumeOptions.class.cast(object);
|
||||||
|
return equal(volumeType, other.volumeType) && equal(availabilityZone, other.availabilityZone) && equal(snapshotId, other.snapshotId)
|
||||||
|
&& equal(name, other.name) && equal(description, other.description) && equal(metadata, other.metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(volumeType, availabilityZone, snapshotId, name, description, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToStringHelper string() {
|
||||||
|
return toStringHelper("").add("volumeType", volumeType).add("availabilityZone", availabilityZone)
|
||||||
|
.add("snapshotId", snapshotId).add("name", name).add("description", description).add("metadata", metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return string().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom cloud server metadata can also be supplied at launch time. This
|
||||||
|
* metadata is stored in the API system where it is retrievable by querying
|
||||||
|
* the API for server status. The maximum size of the metadata key and value
|
||||||
|
* is each 255 bytes and the maximum number of key-value pairs that can be
|
||||||
|
* supplied per volume is 5.
|
||||||
|
*/
|
||||||
|
public CreateVolumeOptions metadata(Map<String, String> metadata) {
|
||||||
|
checkNotNull(metadata, "metadata");
|
||||||
|
checkArgument(metadata.size() <= 5,
|
||||||
|
"you cannot have more then 5 metadata values. You specified: " + metadata.size());
|
||||||
|
for (Entry<String, String> entry : metadata.entrySet()) {
|
||||||
|
checkArgument(
|
||||||
|
entry.getKey().getBytes().length < 255,
|
||||||
|
String.format("maximum length of metadata key is 255 bytes. Key specified %s is %d bytes",
|
||||||
|
entry.getKey(), entry.getKey().getBytes().length));
|
||||||
|
checkArgument(entry.getKey().getBytes().length < 255, String.format(
|
||||||
|
"maximum length of metadata value is 255 bytes. Value specified for %s (%s) is %d bytes",
|
||||||
|
entry.getKey(), entry.getValue(), entry.getValue().getBytes().length));
|
||||||
|
}
|
||||||
|
this.metadata = ImmutableMap.copyOf(metadata);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeOptions name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeOptions description(String description) {
|
||||||
|
this.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeOptions volumeType(String volumeType) {
|
||||||
|
this.volumeType = volumeType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeOptions availabilityZone(String availabilityZone) {
|
||||||
|
this.availabilityZone = availabilityZone;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeOptions snapshotId(String snapshotId) {
|
||||||
|
this.snapshotId = snapshotId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVolumeType() {
|
||||||
|
return volumeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvailabilityZone() {
|
||||||
|
return availabilityZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSnapshotId() {
|
||||||
|
return snapshotId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeOptions#getName()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeOptions name(String name) {
|
||||||
|
return new CreateVolumeOptions().name(name);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeOptions#getDescription()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeOptions description(String description) {
|
||||||
|
return new CreateVolumeOptions().description(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeOptions#getVolumeType()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeOptions volumeType(String volumeType) {
|
||||||
|
return new CreateVolumeOptions().volumeType(volumeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeOptions#getAvailabilityZone()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeOptions availabilityZone(String availabilityZone) {
|
||||||
|
return new CreateVolumeOptions().availabilityZone(availabilityZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeOptions#getSnapshotId()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeOptions snapshotId(String snapshotId) {
|
||||||
|
return new CreateVolumeOptions().snapshotId(snapshotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeOptions#getMetadata()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeOptions metadata(Map<String, String> metadata) {
|
||||||
|
return new CreateVolumeOptions().metadata(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.options;
|
||||||
|
|
||||||
|
import static com.google.common.base.Objects.equal;
|
||||||
|
import static com.google.common.base.Objects.toStringHelper;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.rest.MapBinder;
|
||||||
|
import org.jclouds.rest.binders.BindToJsonPayload;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Objects.ToStringHelper;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
public class CreateVolumeSnapshotOptions implements MapBinder {
|
||||||
|
public static final CreateVolumeSnapshotOptions NONE = new CreateVolumeSnapshotOptions();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BindToJsonPayload jsonBinder;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private boolean force = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
|
||||||
|
Map<String, String> data = Maps.newHashMap(postParams);
|
||||||
|
if (name != null)
|
||||||
|
data.put("display_name", name);
|
||||||
|
if (description != null)
|
||||||
|
data.put("display_description", description);
|
||||||
|
if (force)
|
||||||
|
data.put("force", "true");
|
||||||
|
return jsonBinder.bindToRequest(request, ImmutableMap.of("snapshot", data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
|
||||||
|
throw new IllegalStateException("CreateSnapshot is a POST operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(object instanceof CreateVolumeSnapshotOptions)) return false;
|
||||||
|
final CreateVolumeSnapshotOptions other = CreateVolumeSnapshotOptions.class.cast(object);
|
||||||
|
return equal(name, other.name) && equal(description, other.description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(name, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToStringHelper string() {
|
||||||
|
return toStringHelper("").add("name", name).add("description", description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return string().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeSnapshotOptions name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeSnapshotOptions description(String description) {
|
||||||
|
this.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateVolumeSnapshotOptions force() {
|
||||||
|
this.force = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeSnapshotOptions#getName()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeSnapshotOptions name(String name) {
|
||||||
|
return new CreateVolumeSnapshotOptions().name(name);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeSnapshotOptions#getDescription()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeSnapshotOptions description(String description) {
|
||||||
|
return new CreateVolumeSnapshotOptions().description(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see CreateVolumeSnapshotOptions#isForce()
|
||||||
|
*/
|
||||||
|
public static CreateVolumeSnapshotOptions force() {
|
||||||
|
return new CreateVolumeSnapshotOptions().force();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -76,7 +76,6 @@ public class NovaErrorHandlerTest {
|
||||||
IllegalStateException.class);
|
IllegalStateException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test400MakesInsufficientResourcesExceptionOnQuotaExceeded() {
|
public void test400MakesInsufficientResourcesExceptionOnQuotaExceeded() {
|
||||||
assertCodeMakes(
|
assertCodeMakes(
|
||||||
|
@ -88,6 +87,17 @@ public class NovaErrorHandlerTest {
|
||||||
InsufficientResourcesException.class);
|
InsufficientResourcesException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test413MakesInsufficientResourcesException() {
|
||||||
|
assertCodeMakes(
|
||||||
|
"POST",
|
||||||
|
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/os-volumes"),
|
||||||
|
413,
|
||||||
|
"HTTP/1.1 413 Request Entity Too Large",
|
||||||
|
"{\"badRequest\": {\"message\": \"Volume quota exceeded. You cannot create a volume of size 1G\", \"code\": 413, \"retryAfter\": 0}}",
|
||||||
|
InsufficientResourcesException.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test404MakesResourceNotFoundException() {
|
public void test404MakesResourceNotFoundException() {
|
||||||
assertCodeMakes("GET", URI.create("https://api.openstack.nova.com/foo"), 404, "", "Not Found",
|
assertCodeMakes("GET", URI.create("https://api.openstack.nova.com/foo"), 404, "", "Not Found",
|
||||||
|
|
|
@ -28,15 +28,11 @@ import java.util.Set;
|
||||||
import org.jclouds.openstack.nova.v1_1.domain.Address;
|
import org.jclouds.openstack.nova.v1_1.domain.Address;
|
||||||
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
|
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
|
||||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||||
import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
|
|
||||||
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
|
|
||||||
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
|
|
||||||
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
|
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
|
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,8 +106,7 @@ public class FloatingIPClientLiveTest extends BaseNovaClientLiveTest {
|
||||||
continue;
|
continue;
|
||||||
FloatingIPClient client = clientOption.get();
|
FloatingIPClient client = clientOption.get();
|
||||||
ServerClient serverClient = novaContext.getApi().getServerClientForZone(zoneId);
|
ServerClient serverClient = novaContext.getApi().getServerClientForZone(zoneId);
|
||||||
Server server = serverClient.createServer("test", imageIdForZone(zoneId), flavorRefForZone(zoneId));
|
Server server = createServerInZone(zoneId);
|
||||||
blockUntilServerActive(server.getId(), serverClient);
|
|
||||||
FloatingIP floatingIP = client.allocate();
|
FloatingIP floatingIP = client.allocate();
|
||||||
assertNotNull(floatingIP);
|
assertNotNull(floatingIP);
|
||||||
try {
|
try {
|
||||||
|
@ -124,25 +119,6 @@ public class FloatingIPClientLiveTest extends BaseNovaClientLiveTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String imageIdForZone(String zoneId) {
|
|
||||||
ImageClient imageClient = novaContext.getApi().getImageClientForZone(zoneId);
|
|
||||||
return Iterables.getLast(imageClient.listImages()).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String flavorRefForZone(String zoneId) {
|
|
||||||
FlavorClient flavorClient = novaContext.getApi().getFlavorClientForZone(zoneId);
|
|
||||||
return Iterables.getLast(flavorClient.listFlavors()).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void blockUntilServerActive(String serverId, ServerClient client) throws InterruptedException {
|
|
||||||
Server currentDetails = null;
|
|
||||||
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != Status.ACTIVE; currentDetails = client
|
|
||||||
.getServer(serverId)) {
|
|
||||||
System.out.printf("blocking on status active%n%s%n", currentDetails);
|
|
||||||
Thread.sleep(5 * 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void assertEventually(Runnable assertion) {
|
protected static void assertEventually(Runnable assertion) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
AssertionError error = null;
|
AssertionError error = null;
|
||||||
|
|
|
@ -0,0 +1,458 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.extensions;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.date.DateService;
|
||||||
|
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.Volume;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeSnapshot;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeOptions;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeSnapshotOptions;
|
||||||
|
import org.jclouds.rest.AuthorizationException;
|
||||||
|
import org.jclouds.rest.ResourceNotFoundException;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests VolumeClient guice wiring and parsing
|
||||||
|
*
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "VolumeClientExpectTest")
|
||||||
|
public class VolumeClientExpectTest extends BaseNovaClientExpectTest {
|
||||||
|
private DateService dateService = new SimpleDateFormatDateService();
|
||||||
|
|
||||||
|
public void testListVolumes() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/volume_list.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<Volume> volumes = client.listVolumes();
|
||||||
|
assertEquals(volumes, ImmutableSet.of(testVolume()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListVolumesFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<Volume> volumes = client.listVolumes();
|
||||||
|
assertTrue(volumes.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListVolumesInDetail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes/detail");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/volume_list_detail.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<Volume> volumes = client.listVolumesInDetail();
|
||||||
|
assertEquals(volumes, ImmutableSet.of(testVolume()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListVolumesInDetailFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes/detail");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<Volume> volumes = client.listVolumesInDetail();
|
||||||
|
assertTrue(volumes.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateVolume() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint)
|
||||||
|
.method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"volume\":{\"display_name\":\"jclouds-test-volume\",\"display_description\":\"description of test volume\",\"size\":\"1\"}}", MediaType.APPLICATION_JSON))
|
||||||
|
.build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/volume_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Volume volume = client.createVolume(1, CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume"));
|
||||||
|
assertEquals(volume, testVolume());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||||
|
public void testCreateVolumeFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint)
|
||||||
|
.endpoint(endpoint)
|
||||||
|
.method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"volume\":{\"display_name\":\"jclouds-test-volume\",\"display_description\":\"description of test volume\",\"size\":\"1\"}}", MediaType.APPLICATION_JSON))
|
||||||
|
.build(),
|
||||||
|
standardResponseBuilder(404).payload(payloadFromResource("/volume_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
client.createVolume(1, CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetVolume() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/volume_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Volume volume = client.getVolume("1");
|
||||||
|
assertEquals(volume, testVolume());
|
||||||
|
// double-check equals()
|
||||||
|
assertEquals(volume.getStatus(), Volume.Status.IN_USE);
|
||||||
|
assertEquals(volume.getDescription(), "This is a test volume");
|
||||||
|
assertEquals(volume.getZone(), "nova");
|
||||||
|
assertEquals(volume.getName(), "test");
|
||||||
|
assertEquals(volume.getStatus(), Volume.Status.IN_USE);
|
||||||
|
assertEquals(Iterables.getOnlyElement(volume.getAttachments()), testAttachment());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetVolumeFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertNull(client.getVolume("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDeleteVolume() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("DELETE").build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/attachment_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertTrue(client.deleteVolume("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDeleteVolumeFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-volumes/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("DELETE").build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertFalse(client.deleteVolume("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListAttachments() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-1/os-volume_attachments");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/attachment_list.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<VolumeAttachment> attachments = client.listAttachmentsOnServer("instance-1");
|
||||||
|
assertEquals(attachments, ImmutableSet.of(testAttachment()));
|
||||||
|
// double-check individual fields
|
||||||
|
VolumeAttachment attachment = Iterables.getOnlyElement(attachments);
|
||||||
|
assertEquals(attachment.getDevice(), "/dev/vdc");
|
||||||
|
assertEquals(attachment.getServerId(), "b4785058-cb80-491b-baa3-e4ee6546450e");
|
||||||
|
assertEquals(attachment.getId(), "1");
|
||||||
|
assertEquals(attachment.getVolumeId(), "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = AuthorizationException.class)
|
||||||
|
public void testListAttachmentsFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-2/os-volume_attachments");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(401).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
client.listAttachmentsOnServer("instance-2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAttachment() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/attachment_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
VolumeAttachment attachment = client.getAttachmentForVolumeOnServer("1", "instance-1");
|
||||||
|
assertEquals(attachment, testAttachment());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetAttachmentFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertNull(client.getAttachmentForVolumeOnServer("1", "instance-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAttachVolume() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-1/os-volume_attachments");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"volumeAttachment\":{\"volumeId\":\"1\",\"device\":\"/dev/vdc\"}}", MediaType.APPLICATION_JSON)).endpoint(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/attachment_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
VolumeAttachment result = client.attachVolumeToServerAsDevice("1", "instance-1", "/dev/vdc");
|
||||||
|
assertEquals(result, testAttachment());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||||
|
public void testAttachVolumeFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-1/os-volume_attachments");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"volumeAttachment\":{\"volumeId\":\"1\",\"device\":\"/dev/vdc\"}}", MediaType.APPLICATION_JSON)).endpoint(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
client.attachVolumeToServerAsDevice("1", "instance-1","/dev/vdc");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetachVolume() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("DELETE").build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/attachment_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertTrue(client.detachVolumeFromServer("1", "instance-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetachVolumeFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/instance-1/os-volume_attachments/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("DELETE").build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertFalse(client.detachVolumeFromServer("1", "instance-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListSnapshots() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/snapshot_list.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<VolumeSnapshot> snapshots = client.listSnapshots();
|
||||||
|
assertEquals(snapshots, ImmutableSet.of(testSnapshot()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListSnapshotsFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<VolumeSnapshot> snapshots = client.listSnapshots();
|
||||||
|
assertTrue(snapshots.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetSnapshot() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/snapshot_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
VolumeSnapshot snapshot = client.getSnapshot("1");
|
||||||
|
assertEquals(snapshot, testSnapshot());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetSnapshotFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertNull(client.getSnapshot("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListSnapshotsInDetail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots/detail");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/snapshot_list_detail.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<VolumeSnapshot> snapshots = client.listSnapshotsInDetail();
|
||||||
|
assertEquals(snapshots, ImmutableSet.of(testSnapshot()));
|
||||||
|
|
||||||
|
// double-check individual fields
|
||||||
|
VolumeSnapshot snappy = Iterables.getOnlyElement(snapshots);
|
||||||
|
assertEquals(snappy.getId(), "7");
|
||||||
|
assertEquals(snappy.getVolumeId(), "9");
|
||||||
|
assertEquals(snappy.getStatus(), Volume.Status.AVAILABLE);
|
||||||
|
assertEquals(snappy.getDescription(), "jclouds live test snapshot");
|
||||||
|
assertEquals(snappy.getName(), "jclouds-live-test");
|
||||||
|
assertEquals(snappy.getSize(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListSnapshotsInDetailFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots/detail");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).build(),
|
||||||
|
standardResponseBuilder(404).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
Set<VolumeSnapshot> snapshots = client.listSnapshotsInDetail();
|
||||||
|
assertTrue(snapshots.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateSnapshot() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint)
|
||||||
|
.method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"snapshot\":{\"display_name\":\"jclouds-live-test\",\"volume_id\":\"13\",\"display_description\":\"jclouds live test snapshot\",\"force\":\"true\"}}", MediaType.APPLICATION_JSON))
|
||||||
|
.build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/snapshot_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
VolumeSnapshot snapshot = client.createSnapshot("13", CreateVolumeSnapshotOptions.Builder.name("jclouds-live-test").description("jclouds live test snapshot").force());
|
||||||
|
assertEquals(snapshot, testSnapshot());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = AuthorizationException.class)
|
||||||
|
public void testCreateSnapshotFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint)
|
||||||
|
.method("POST")
|
||||||
|
.payload(payloadFromStringWithContentType("{\"snapshot\":{\"display_name\":\"jclouds-live-test\",\"volume_id\":\"13\",\"display_description\":\"jclouds live test snapshot\",\"force\":\"true\"}}", MediaType.APPLICATION_JSON))
|
||||||
|
.build(),
|
||||||
|
standardResponseBuilder(401).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
client.createSnapshot("13", CreateVolumeSnapshotOptions.Builder.name("jclouds-live-test").description("jclouds live test snapshot").force());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDeleteSnapshot() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("DELETE").build(),
|
||||||
|
standardResponseBuilder(200).payload(payloadFromResource("/snapshot_details.json")).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
assertTrue(client.deleteSnapshot("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = AuthorizationException.class)
|
||||||
|
public void testDeleteSnapshotFail() {
|
||||||
|
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-snapshots/1");
|
||||||
|
VolumeClient client = requestsSendResponses(
|
||||||
|
keystoneAuthWithUsernameAndPassword,
|
||||||
|
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
|
||||||
|
standardRequestBuilder(endpoint).method("DELETE").build(),
|
||||||
|
standardResponseBuilder(401).build()
|
||||||
|
).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
|
||||||
|
|
||||||
|
client.deleteSnapshot("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Volume testVolume() {
|
||||||
|
return Volume.builder().status(Volume.Status.IN_USE).description("This is a test volume").zone("nova").name("test")
|
||||||
|
.attachments(ImmutableSet.of(testAttachment())).size(1).id("1").created(dateService.iso8601SecondsDateParse("2012-04-23 12:16:45")).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected VolumeAttachment testAttachment() {
|
||||||
|
return VolumeAttachment.builder().device("/dev/vdc").serverId("b4785058-cb80-491b-baa3-e4ee6546450e").id("1").volumeId("1").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected VolumeSnapshot testSnapshot() {
|
||||||
|
return VolumeSnapshot.builder().id("7").volumeId("9").description("jclouds live test snapshot").status(Volume.Status.AVAILABLE)
|
||||||
|
.name("jclouds-live-test").size(1).created(dateService.iso8601SecondsDateParse("2012-04-24 13:34:42")).build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,283 @@
|
||||||
|
/**
|
||||||
|
* 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.openstack.nova.v1_1.extensions;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.Volume;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeAttachment;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.VolumeSnapshot;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeOptions;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.options.CreateVolumeSnapshotOptions;
|
||||||
|
import org.jclouds.predicates.RetryablePredicate;
|
||||||
|
import org.testng.annotations.AfterGroups;
|
||||||
|
import org.testng.annotations.BeforeGroups;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of VolumeClient
|
||||||
|
*
|
||||||
|
* @author Adam Lowe
|
||||||
|
*/
|
||||||
|
@Test(groups = "live", testName = "VolumeClientLiveTest", singleThreaded = true)
|
||||||
|
public class VolumeClientLiveTest extends BaseNovaClientLiveTest {
|
||||||
|
|
||||||
|
private Optional<VolumeClient> volumeOption;
|
||||||
|
private String zone;
|
||||||
|
|
||||||
|
private Volume testVolume;
|
||||||
|
private VolumeSnapshot testSnapshot;
|
||||||
|
|
||||||
|
@BeforeGroups(groups = { "integration", "live" })
|
||||||
|
@Override
|
||||||
|
public void setupContext() {
|
||||||
|
super.setupContext();
|
||||||
|
zone = Iterables.getLast(novaContext.getApi().getConfiguredZones(), "nova");
|
||||||
|
volumeOption = novaContext.getApi().getVolumeExtensionForZone(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterGroups(groups = "live", alwaysRun = true)
|
||||||
|
@Override
|
||||||
|
protected void tearDown() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
if (testSnapshot != null) {
|
||||||
|
final String snapshotId = testSnapshot.getId();
|
||||||
|
assertTrue(volumeOption.get().deleteSnapshot(snapshotId));
|
||||||
|
assertTrue(new RetryablePredicate<VolumeClient>(new Predicate<VolumeClient>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeClient volumeClient) {
|
||||||
|
return volumeOption.get().getSnapshot(snapshotId) == null;
|
||||||
|
}
|
||||||
|
}, 30 * 1000L).apply(volumeOption.get()));
|
||||||
|
}
|
||||||
|
if (testVolume != null) {
|
||||||
|
final String volumeId = testVolume.getId();
|
||||||
|
assertTrue(volumeOption.get().deleteVolume(volumeId));
|
||||||
|
assertTrue(new RetryablePredicate<VolumeClient>(new Predicate<VolumeClient>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeClient volumeClient) {
|
||||||
|
return volumeOption.get().getVolume(volumeId) == null;
|
||||||
|
}
|
||||||
|
}, 180 * 1000L).apply(volumeOption.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateVolume() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
testVolume = volumeOption.get().createVolume(
|
||||||
|
1,
|
||||||
|
CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume")
|
||||||
|
.availabilityZone(zone));
|
||||||
|
assertTrue(new RetryablePredicate<VolumeClient>(new Predicate<VolumeClient>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeClient volumeClient) {
|
||||||
|
return volumeOption.get().getVolume(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE;
|
||||||
|
}
|
||||||
|
}, 180 * 1000L).apply(volumeOption.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testCreateVolume")
|
||||||
|
public void testListVolumes() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
Set<Volume> volumes = volumeOption.get().listVolumes();
|
||||||
|
assertNotNull(volumes);
|
||||||
|
boolean foundIt = false;
|
||||||
|
for (Volume vol : volumes) {
|
||||||
|
Volume details = volumeOption.get().getVolume(vol.getId());
|
||||||
|
assertNotNull(details);
|
||||||
|
if (Objects.equal(details.getId(), testVolume.getId())) {
|
||||||
|
foundIt = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(foundIt, "Failed to find the volume we created in listVolumes() response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testCreateVolume")
|
||||||
|
public void testListVolumesInDetail() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
Set<Volume> volumes = volumeOption.get().listVolumesInDetail();
|
||||||
|
assertNotNull(volumes);
|
||||||
|
assertTrue(volumes.contains(testVolume));
|
||||||
|
boolean foundIt = false;
|
||||||
|
for (Volume vol : volumes) {
|
||||||
|
Volume details = volumeOption.get().getVolume(vol.getId());
|
||||||
|
assertNotNull(details);
|
||||||
|
assertNotNull(details.getId());
|
||||||
|
assertNotNull(details.getCreated());
|
||||||
|
assertTrue(details.getSize() > -1);
|
||||||
|
|
||||||
|
assertEquals(details.getId(), vol.getId());
|
||||||
|
assertEquals(details.getSize(), vol.getSize());
|
||||||
|
assertEquals(details.getName(), vol.getName());
|
||||||
|
assertEquals(details.getDescription(), vol.getDescription());
|
||||||
|
assertEquals(details.getCreated(), vol.getCreated());
|
||||||
|
if (Objects.equal(details.getId(), testVolume.getId())) {
|
||||||
|
foundIt = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(foundIt, "Failed to find the volume we previously created in listVolumesInDetail() response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testCreateVolume")
|
||||||
|
public void testCreateSnapshot() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
testSnapshot = volumeOption.get().createSnapshot(
|
||||||
|
testVolume.getId(),
|
||||||
|
CreateVolumeSnapshotOptions.Builder.name("jclouds-live-test").description(
|
||||||
|
"jclouds live test snapshot").force());
|
||||||
|
assertNotNull(testSnapshot);
|
||||||
|
assertNotNull(testSnapshot.getId());
|
||||||
|
final String snapshotId = testSnapshot.getId();
|
||||||
|
assertNotNull(testSnapshot.getStatus());
|
||||||
|
assertTrue(testSnapshot.getSize() > -1);
|
||||||
|
assertNotNull(testSnapshot.getCreated());
|
||||||
|
|
||||||
|
assertTrue(new RetryablePredicate<VolumeClient>(new Predicate<VolumeClient>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeClient volumeClient) {
|
||||||
|
return volumeOption.get().getSnapshot(snapshotId).getStatus() == Volume.Status.AVAILABLE;
|
||||||
|
}
|
||||||
|
}, 30 * 1000L).apply(volumeOption.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testCreateSnapshot")
|
||||||
|
public void testListSnapshots() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
Set<VolumeSnapshot> snapshots = volumeOption.get().listSnapshots();
|
||||||
|
assertNotNull(snapshots);
|
||||||
|
boolean foundIt = false;
|
||||||
|
for (VolumeSnapshot snap : snapshots) {
|
||||||
|
VolumeSnapshot details = volumeOption.get().getSnapshot(snap.getId());
|
||||||
|
if (Objects.equal(snap.getVolumeId(), testVolume.getId())) {
|
||||||
|
foundIt = true;
|
||||||
|
}
|
||||||
|
assertNotNull(details);
|
||||||
|
assertEquals(details.getId(), snap.getId());
|
||||||
|
assertEquals(details.getVolumeId(), snap.getVolumeId());
|
||||||
|
}
|
||||||
|
assertTrue(foundIt, "Failed to find the snapshot we previously created in listSnapshots() response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testCreateSnapshot")
|
||||||
|
public void testListSnapshotsInDetail() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
Set<VolumeSnapshot> snapshots = volumeOption.get().listSnapshotsInDetail();
|
||||||
|
assertNotNull(snapshots);
|
||||||
|
boolean foundIt = false;
|
||||||
|
for (VolumeSnapshot snap : snapshots) {
|
||||||
|
VolumeSnapshot details = volumeOption.get().getSnapshot(snap.getId());
|
||||||
|
if (Objects.equal(snap.getVolumeId(), testVolume.getId())) {
|
||||||
|
foundIt = true;
|
||||||
|
assertSame(details, testSnapshot);
|
||||||
|
}
|
||||||
|
assertSame(details, snap);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(foundIt, "Failed to find the snapshot we created in listSnapshotsInDetail() response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSame(VolumeSnapshot a, VolumeSnapshot b) {
|
||||||
|
assertNotNull(a);
|
||||||
|
assertNotNull(b);
|
||||||
|
assertEquals(a.getId(), b.getId());
|
||||||
|
assertEquals(a.getDescription(), b.getDescription());
|
||||||
|
assertEquals(a.getName(), b.getName());
|
||||||
|
assertEquals(a.getVolumeId(), b.getVolumeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testCreateVolume")
|
||||||
|
public void testAttachments() {
|
||||||
|
if (volumeOption.isPresent()) {
|
||||||
|
String server_id = null;
|
||||||
|
try {
|
||||||
|
final String serverId = server_id = createServerInZone(zone).getId();
|
||||||
|
|
||||||
|
Set<VolumeAttachment> attachments = volumeOption.get().listAttachmentsOnServer(serverId);
|
||||||
|
assertNotNull(attachments);
|
||||||
|
final int before = attachments.size();
|
||||||
|
|
||||||
|
VolumeAttachment testAttachment = volumeOption.get().attachVolumeToServerAsDevice(testVolume.getId(),
|
||||||
|
serverId, "/dev/vdf");
|
||||||
|
assertNotNull(testAttachment.getId());
|
||||||
|
assertEquals(testAttachment.getVolumeId(), testVolume.getId());
|
||||||
|
|
||||||
|
assertTrue(new RetryablePredicate<VolumeClient>(new Predicate<VolumeClient>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeClient volumeClient) {
|
||||||
|
return volumeOption.get().listAttachmentsOnServer(serverId).size() == before + 1;
|
||||||
|
}
|
||||||
|
}, 60 * 1000L).apply(volumeOption.get()));
|
||||||
|
|
||||||
|
attachments = volumeOption.get().listAttachmentsOnServer(serverId);
|
||||||
|
assertNotNull(attachments);
|
||||||
|
assertEquals(attachments.size(), before + 1);
|
||||||
|
|
||||||
|
assertEquals(volumeOption.get().getVolume(testVolume.getId()).getStatus(), Volume.Status.IN_USE);
|
||||||
|
|
||||||
|
boolean foundIt = false;
|
||||||
|
for (VolumeAttachment att : attachments) {
|
||||||
|
VolumeAttachment details = volumeOption.get()
|
||||||
|
.getAttachmentForVolumeOnServer(att.getVolumeId(), serverId);
|
||||||
|
assertNotNull(details);
|
||||||
|
assertNotNull(details.getId());
|
||||||
|
assertNotNull(details.getServerId());
|
||||||
|
assertNotNull(details.getVolumeId());
|
||||||
|
if (Objects.equal(details.getVolumeId(), testVolume.getId())) {
|
||||||
|
foundIt = true;
|
||||||
|
assertEquals(details.getDevice(), "/dev/vdf");
|
||||||
|
assertEquals(details.getServerId(), serverId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(foundIt, "Failed to find the attachment we created in listAttachments() response");
|
||||||
|
|
||||||
|
volumeOption.get().detachVolumeFromServer(testVolume.getId(), serverId);
|
||||||
|
assertTrue(new RetryablePredicate<VolumeClient>(new Predicate<VolumeClient>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(VolumeClient volumeClient) {
|
||||||
|
return volumeOption.get().listAttachmentsOnServer(serverId).size() == before;
|
||||||
|
}
|
||||||
|
}, 60 * 1000L).apply(volumeOption.get()));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (server_id != null)
|
||||||
|
novaContext.getApi().getServerClientForZone(zone).deleteServer(server_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,11 +25,19 @@ import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
|
||||||
import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
|
import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||||
import org.jclouds.openstack.nova.v1_1.config.NovaProperties;
|
import org.jclouds.openstack.nova.v1_1.config.NovaProperties;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
|
||||||
import org.jclouds.rest.RestContext;
|
import org.jclouds.rest.RestContext;
|
||||||
import org.testng.annotations.AfterGroups;
|
import org.testng.annotations.AfterGroups;
|
||||||
import org.testng.annotations.BeforeGroups;
|
import org.testng.annotations.BeforeGroups;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests behavior of {@code NovaClient}
|
* Tests behavior of {@code NovaClient}
|
||||||
*
|
*
|
||||||
|
@ -65,4 +73,34 @@ public class BaseNovaClientLiveTest extends BaseComputeServiceContextLiveTest {
|
||||||
novaContext.close();
|
novaContext.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Server createServerInZone(String zoneId) {
|
||||||
|
ServerClient serverClient = novaContext.getApi().getServerClientForZone(zoneId);
|
||||||
|
Server server = serverClient.createServer("test", imageIdForZone(zoneId), flavorRefForZone(zoneId));
|
||||||
|
blockUntilServerActive(server.getId(), serverClient);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void blockUntilServerActive(String serverId, ServerClient client) {
|
||||||
|
Server currentDetails = null;
|
||||||
|
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != Status.ACTIVE; currentDetails = client
|
||||||
|
.getServer(serverId)) {
|
||||||
|
System.out.printf("blocking on status active%n%s%n", currentDetails);
|
||||||
|
try {
|
||||||
|
Thread.sleep(5 * 1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw Throwables.propagate(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String imageIdForZone(String zoneId) {
|
||||||
|
ImageClient imageClient = novaContext.getApi().getImageClientForZone(zoneId);
|
||||||
|
return Iterables.getLast(imageClient.listImages()).getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String flavorRefForZone(String zoneId) {
|
||||||
|
FlavorClient flavorClient = novaContext.getApi().getFlavorClientForZone(zoneId);
|
||||||
|
return Iterables.getLast(flavorClient.listFlavors()).getId();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.jclouds.openstack.nova.v1_1.internal;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.http.HttpResponse;
|
import org.jclouds.http.HttpResponse;
|
||||||
import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
|
import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
|
||||||
|
@ -68,4 +70,14 @@ public class BaseNovaExpectTest<T> extends BaseRestClientExpectTest<T> {
|
||||||
unmatchedExtensionsOfNovaResponse = HttpResponse.builder().statusCode(200)
|
unmatchedExtensionsOfNovaResponse = HttpResponse.builder().statusCode(200)
|
||||||
.payload(payloadFromResource("/extension_list.json")).build();
|
.payload(payloadFromResource("/extension_list.json")).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected HttpRequest.Builder standardRequestBuilder(URI endpoint) {
|
||||||
|
return HttpRequest.builder().method("GET")
|
||||||
|
.headers(ImmutableMultimap.of("Accept", MediaType.APPLICATION_JSON, "X-Auth-Token", authToken))
|
||||||
|
.endpoint(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpResponse.Builder standardResponseBuilder(int status) {
|
||||||
|
return HttpResponse.builder().statusCode(status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"volumeAttachment": {"device": "/dev/vdc", "serverId": "b4785058-cb80-491b-baa3-e4ee6546450e", "id": 1, "volumeId": 1}}
|
|
@ -0,0 +1 @@
|
||||||
|
{"volumeAttachments": [{"device": "/dev/vdc", "serverId": "b4785058-cb80-491b-baa3-e4ee6546450e", "id": 1, "volumeId": 1}]}
|
|
@ -0,0 +1 @@
|
||||||
|
{"snapshot": {"status": "available", "displayDescription": "jclouds live test snapshot", "displayName": "jclouds-live-test", "volumeId": 9, "id": 7, "createdAt": "2012-04-24 13:34:42", "size": 1}}
|
|
@ -0,0 +1 @@
|
||||||
|
{"snapshots": [{"status": "available", "displayDescription": "jclouds live test snapshot", "displayName": "jclouds-live-test", "volumeId": 9, "id": 7, "createdAt": "2012-04-24 13:34:42", "size": 1}]}
|
|
@ -0,0 +1 @@
|
||||||
|
{"snapshots": [{"status": "available", "displayDescription": "jclouds live test snapshot", "displayName": "jclouds-live-test", "volumeId": 9, "id": 7, "createdAt": "2012-04-24 13:34:42", "size": 1}]}
|
|
@ -0,0 +1 @@
|
||||||
|
{"volume": {"status": "in-use", "displayDescription": "This is a test volume", "availabilityZone": "nova", "displayName": "test", "attachments": [{"device": "/dev/vdc", "serverId": "b4785058-cb80-491b-baa3-e4ee6546450e", "id": 1, "volumeId": 1}], "volumeType": null, "snapshotId": null, "size": 1, "id": 1, "createdAt": "2012-04-23 12:16:45", "metadata": {}}}
|
|
@ -0,0 +1 @@
|
||||||
|
{"volumes": [{"status": "in-use", "displayDescription": "This is a test volume", "availabilityZone": "nova", "displayName": "test", "attachments": [{"device": "/dev/vdc", "serverId": "b4785058-cb80-491b-baa3-e4ee6546450e", "id": 1, "volumeId": 1}], "volumeType": null, "snapshotId": null, "size": 1, "id": 1, "createdAt": "2012-04-23 12:16:45", "metadata": {}}]}
|
|
@ -0,0 +1 @@
|
||||||
|
{"volumes": [{"status": "in-use", "displayDescription": "This is a test volume", "availabilityZone": "nova", "displayName": "test", "attachments": [{"device": "/dev/vdc", "serverId": "b4785058-cb80-491b-baa3-e4ee6546450e", "id": 1, "volumeId": 1}], "volumeType": null, "snapshotId": null, "size": 1, "id": 1, "createdAt": "2012-04-23 12:16:45", "metadata": {}}]}
|
|
@ -118,7 +118,7 @@ Options can also be specified for extension modules
|
||||||
(modules (apply modules (concat ext-modules (opts :extensions))))
|
(modules (apply modules (concat ext-modules (opts :extensions))))
|
||||||
(overrides (reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
|
(overrides (reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
|
||||||
(Properties.) (dissoc opts :extensions)))
|
(Properties.) (dissoc opts :extensions)))
|
||||||
(build BlobStoreContext))]
|
(buildView BlobStoreContext))]
|
||||||
(if (some #(= :async %) options)
|
(if (some #(= :async %) options)
|
||||||
(.getAsyncBlobStore context)
|
(.getAsyncBlobStore context)
|
||||||
(.getBlobStore context)))))
|
(.getBlobStore context)))))
|
||||||
|
|
|
@ -90,7 +90,7 @@ Here's an example of creating and running a small linux node in the group webser
|
||||||
(modules (apply modules (concat ext-modules (opts :extensions))))
|
(modules (apply modules (concat ext-modules (opts :extensions))))
|
||||||
(overrides (reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
|
(overrides (reduce #(do (.put %1 (name (first %2)) (second %2)) %1)
|
||||||
(Properties.) (dissoc opts :extensions)))
|
(Properties.) (dissoc opts :extensions)))
|
||||||
(build ComputeServiceContext)
|
(buildView ComputeServiceContext)
|
||||||
(getComputeService))))
|
(getComputeService))))
|
||||||
([#^ComputeServiceContext compute-context]
|
([#^ComputeServiceContext compute-context]
|
||||||
(.getComputeService compute-context)))
|
(.getComputeService compute-context)))
|
||||||
|
|
|
@ -231,6 +231,8 @@ public class ContextBuilder {
|
||||||
try {
|
try {
|
||||||
return find(newArrayList(mutable.getProperty(prov + "." + key), mutable.getProperty("jclouds." + key)),
|
return find(newArrayList(mutable.getProperty(prov + "." + key), mutable.getProperty("jclouds." + key)),
|
||||||
notNull());
|
notNull());
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
throw new NoSuchElementException(String.format("property %s.%s not present in properties: %s", prov, key, mutable.keySet()));
|
||||||
} finally {
|
} finally {
|
||||||
mutable.remove(prov + "." + key);
|
mutable.remove(prov + "." + key);
|
||||||
mutable.remove("jclouds." + key);
|
mutable.remove("jclouds." + key);
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jclouds</groupId>
|
||||||
|
<artifactId>jclouds-project</artifactId>
|
||||||
|
<version>1.5.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../../project/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<groupId>org.jclouds.labs</groupId>
|
||||||
|
<artifactId>jenkins</artifactId>
|
||||||
|
<name>jcloud jenkins api</name>
|
||||||
|
<description>jclouds components to access an implementation of Jenkins</description>
|
||||||
|
<packaging>bundle</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<test.jenkins.endpoint>http://localhost:8080</test.jenkins.endpoint>
|
||||||
|
<test.jenkins.api-version>1.0</test.jenkins.api-version>
|
||||||
|
<test.jenkins.build-version>1.460</test.jenkins.build-version>
|
||||||
|
<test.jenkins.identity>ANONYMOUS</test.jenkins.identity>
|
||||||
|
<test.jenkins.credential>ANONYMOUS</test.jenkins.credential>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jclouds</groupId>
|
||||||
|
<artifactId>jclouds-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jclouds</groupId>
|
||||||
|
<artifactId>jclouds-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jclouds.driver</groupId>
|
||||||
|
<artifactId>jclouds-slf4j</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>live</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>integration</id>
|
||||||
|
<phase>integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<test.jenkins.endpoint>${test.jenkins.endpoint}</test.jenkins.endpoint>
|
||||||
|
<test.jenkins.api-version>${test.jenkins.api-version}</test.jenkins.api-version>
|
||||||
|
<test.jenkins.build-version>${test.jenkins.build-version}</test.jenkins.build-version>
|
||||||
|
<test.jenkins.identity>${test.jenkins.identity}</test.jenkins.identity>
|
||||||
|
<test.jenkins.credential>${test.jenkins.credential}</test.jenkins.credential>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||||
|
<Export-Package>org.jclouds.jenkins.v1*;version="${project.version}"</Export-Package>
|
||||||
|
<Import-Package>
|
||||||
|
org.jclouds.rest.internal;version="${project.version}",
|
||||||
|
org.jclouds*;version="${project.version}",
|
||||||
|
*
|
||||||
|
</Import-Package>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.jclouds.apis.ApiMetadata;
|
||||||
|
import org.jclouds.jenkins.v1.config.JenkinsRestClientModule;
|
||||||
|
import org.jclouds.rest.RestContext;
|
||||||
|
import org.jclouds.rest.internal.BaseRestApiMetadata;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link ApiMetadata} for Jenkins 1.0 API
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class JenkinsApiMetadata extends BaseRestApiMetadata {
|
||||||
|
|
||||||
|
public static final String ANONYMOUS_IDENTITY = "ANONYMOUS";
|
||||||
|
|
||||||
|
/** The serialVersionUID */
|
||||||
|
private static final long serialVersionUID = 6725672099385580694L;
|
||||||
|
|
||||||
|
public static final TypeToken<RestContext<JenkinsClient, JenkinsAsyncClient>> CONTEXT_TOKEN = new TypeToken<RestContext<JenkinsClient, JenkinsAsyncClient>>() {
|
||||||
|
private static final long serialVersionUID = -5070937833892503232L;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder toBuilder() {
|
||||||
|
return new Builder().fromApiMetadata(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JenkinsApiMetadata() {
|
||||||
|
this(new Builder());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JenkinsApiMetadata(Builder builder) {
|
||||||
|
super(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Properties defaultProperties() {
|
||||||
|
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends BaseRestApiMetadata.Builder {
|
||||||
|
|
||||||
|
protected Builder() {
|
||||||
|
super(JenkinsClient.class, JenkinsAsyncClient.class);
|
||||||
|
id("jenkins")
|
||||||
|
.name("Jenkins API")
|
||||||
|
.identityName("Username (or " + ANONYMOUS_IDENTITY + " if anonymous)")
|
||||||
|
.defaultIdentity(ANONYMOUS_IDENTITY)
|
||||||
|
.credentialName("Password")
|
||||||
|
.defaultCredential(ANONYMOUS_IDENTITY)
|
||||||
|
.documentation(URI.create("https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API"))
|
||||||
|
.version("1.0")
|
||||||
|
.defaultEndpoint("http://localhost:8080")
|
||||||
|
.defaultProperties(JenkinsApiMetadata.defaultProperties())
|
||||||
|
.defaultModules(ImmutableSet.<Class<? extends Module>>of(JenkinsRestClientModule.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JenkinsApiMetadata build() {
|
||||||
|
return new JenkinsApiMetadata(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder fromApiMetadata(ApiMetadata in) {
|
||||||
|
super.fromApiMetadata(in);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1;
|
||||||
|
|
||||||
|
import org.jclouds.jenkins.v1.features.ComputerAsyncClient;
|
||||||
|
import org.jclouds.rest.annotations.Delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous access to Jenkins via their REST API.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @see JenkinsClient
|
||||||
|
* @see <a href="https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API">api doc</a>
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public interface JenkinsAsyncClient {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous access to Computer features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
ComputerAsyncClient getComputerClient();
|
||||||
|
|
||||||
|
}
|
|
@ -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.jenkins.v1;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
import org.jclouds.jenkins.v1.features.ComputerClient;
|
||||||
|
import org.jclouds.rest.annotations.Delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Jenkins.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* @see JenkinsAsyncClient
|
||||||
|
* @see <a href="https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API">api doc</a>
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
|
||||||
|
public interface JenkinsClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides synchronous access to Computer features.
|
||||||
|
*/
|
||||||
|
@Delegate
|
||||||
|
ComputerClient getComputerClient();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration properties and constants used in Jenkins connections.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class JenkinsProperties {
|
||||||
|
|
||||||
|
}
|
|
@ -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.jenkins.v1.config;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpErrorHandler;
|
||||||
|
import org.jclouds.http.annotation.ClientError;
|
||||||
|
import org.jclouds.http.annotation.Redirection;
|
||||||
|
import org.jclouds.http.annotation.ServerError;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsAsyncClient;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsClient;
|
||||||
|
import org.jclouds.jenkins.v1.features.ComputerAsyncClient;
|
||||||
|
import org.jclouds.jenkins.v1.features.ComputerClient;
|
||||||
|
import org.jclouds.jenkins.v1.handlers.JenkinsErrorHandler;
|
||||||
|
import org.jclouds.rest.ConfiguresRestClient;
|
||||||
|
import org.jclouds.rest.config.RestClientModule;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the Jenkins connection.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@ConfiguresRestClient
|
||||||
|
public class JenkinsRestClientModule extends RestClientModule<JenkinsClient, JenkinsAsyncClient> {
|
||||||
|
|
||||||
|
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
|
||||||
|
.put(ComputerClient.class, ComputerAsyncClient.class)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public JenkinsRestClientModule() {
|
||||||
|
super(DELEGATE_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void bindErrorHandlers() {
|
||||||
|
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(JenkinsErrorHandler.class);
|
||||||
|
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(JenkinsErrorHandler.class);
|
||||||
|
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(JenkinsErrorHandler.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
package org.jclouds.jenkins.v1.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Objects.equal;
|
||||||
|
import static com.google.common.base.Objects.toStringHelper;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Objects.ToStringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
* @see <a
|
||||||
|
* href="http://ci.jruby.org/computer/api/">api
|
||||||
|
* doc</a>
|
||||||
|
*/
|
||||||
|
public class Computer implements Comparable<Computer> {
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder toBuilder() {
|
||||||
|
return builder().fromComputerMetadata(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
protected String displayName;
|
||||||
|
protected boolean idle;
|
||||||
|
protected boolean offline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Computer#getDisplayName()
|
||||||
|
*/
|
||||||
|
public Builder displayName(String displayName) {
|
||||||
|
this.displayName = checkNotNull(displayName, "displayName");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Computer#isIdle()
|
||||||
|
*/
|
||||||
|
public Builder idle(boolean idle) {
|
||||||
|
this.idle = idle;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Computer#isOffline()
|
||||||
|
*/
|
||||||
|
public Builder offline(boolean offline) {
|
||||||
|
this.offline = offline;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Computer build() {
|
||||||
|
return new Computer(displayName, idle, offline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder fromComputerMetadata(Computer from) {
|
||||||
|
return displayName(from.getDisplayName()).idle(from.isIdle()).offline(from.isOffline());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String displayName;
|
||||||
|
protected final boolean idle;
|
||||||
|
protected final boolean offline;
|
||||||
|
|
||||||
|
public Computer(String displayName, boolean idle, boolean offline) {
|
||||||
|
this.displayName = checkNotNull(displayName, "displayName");
|
||||||
|
this.idle = idle;
|
||||||
|
this.offline = offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the displayName of the computer
|
||||||
|
*/
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the number of objects in the computer
|
||||||
|
*/
|
||||||
|
public boolean isIdle() {
|
||||||
|
return idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the total offline stored in this computer
|
||||||
|
*/
|
||||||
|
public boolean isOffline() {
|
||||||
|
return offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof Computer) {
|
||||||
|
final Computer other = Computer.class.cast(object);
|
||||||
|
return equal(getDisplayName(), other.getDisplayName()) && equal(isIdle(), other.isIdle())
|
||||||
|
&& equal(isOffline(), other.isOffline());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(getDisplayName(), isIdle(), isOffline());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return string().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToStringHelper string() {
|
||||||
|
return toStringHelper("").add("displayName", getDisplayName()).add("idle", isIdle()).add("offline", isOffline());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Computer that) {
|
||||||
|
if (that == null)
|
||||||
|
return 1;
|
||||||
|
if (this == that)
|
||||||
|
return 0;
|
||||||
|
return this.getDisplayName().compareTo(that.getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
package org.jclouds.jenkins.v1.domain;
|
||||||
|
|
||||||
|
import static com.google.common.base.Objects.equal;
|
||||||
|
import static com.google.common.base.Objects.toStringHelper;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Objects.ToStringHelper;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
* @see <a
|
||||||
|
* href="http://ci.jruby.org/computer/api/">api
|
||||||
|
* doc</a>
|
||||||
|
*/
|
||||||
|
public class ComputerView implements Comparable<ComputerView> {
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder toBuilder() {
|
||||||
|
return builder().fromComputerMetadata(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
protected String displayName;
|
||||||
|
protected int busyExecutors;
|
||||||
|
protected int totalExecutors;
|
||||||
|
protected Set<Computer> computers = ImmutableSet.of();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ComputerView#getDisplayName()
|
||||||
|
*/
|
||||||
|
public Builder displayName(String displayName) {
|
||||||
|
this.displayName = checkNotNull(displayName, "displayName");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ComputerView#getBusyExecutors()
|
||||||
|
*/
|
||||||
|
public Builder busyExecutors(int busyExecutors) {
|
||||||
|
this.busyExecutors = busyExecutors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ComputerView#getTotalExecutors()
|
||||||
|
*/
|
||||||
|
public Builder totalExecutors(int totalExecutors) {
|
||||||
|
this.totalExecutors = totalExecutors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ComputerView#getLinks()
|
||||||
|
*/
|
||||||
|
public Builder computers(Computer... computers) {
|
||||||
|
return computers(ImmutableSet.copyOf(checkNotNull(computers, "computers")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ComputerView#getLinks()
|
||||||
|
*/
|
||||||
|
public Builder computers(Set<Computer> computers) {
|
||||||
|
this.computers = ImmutableSet.copyOf(checkNotNull(computers, "computers"));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComputerView build() {
|
||||||
|
return new ComputerView(displayName, busyExecutors, totalExecutors, computers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder fromComputerMetadata(ComputerView from) {
|
||||||
|
return displayName(from.getDisplayName()).busyExecutors(from.getBusyExecutors()).totalExecutors(from.getTotalExecutors()).computers(from.getComputers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String displayName;
|
||||||
|
protected final int busyExecutors;
|
||||||
|
protected final int totalExecutors;
|
||||||
|
@SerializedName("computer")
|
||||||
|
protected final Set<Computer> computers;
|
||||||
|
|
||||||
|
public ComputerView(String displayName, int busyExecutors, int totalExecutors, Set<Computer> computers) {
|
||||||
|
this.displayName = checkNotNull(displayName, "displayName");
|
||||||
|
this.busyExecutors = busyExecutors;
|
||||||
|
this.totalExecutors = totalExecutors;
|
||||||
|
this.computers = ImmutableSet.copyOf(checkNotNull(computers, "computers"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the displayName of the computer
|
||||||
|
*/
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the number of objects in the computer
|
||||||
|
*/
|
||||||
|
public int getBusyExecutors() {
|
||||||
|
return busyExecutors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the total totalExecutors stored in this computer
|
||||||
|
*/
|
||||||
|
public int getTotalExecutors() {
|
||||||
|
return totalExecutors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the computers in this set
|
||||||
|
*/
|
||||||
|
//TODO: create type adapter for gson that understands ForwardingSet so that we can implement the Set interface
|
||||||
|
public Set<Computer> getComputers() {
|
||||||
|
return computers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof ComputerView) {
|
||||||
|
final ComputerView other = ComputerView.class.cast(object);
|
||||||
|
return equal(getDisplayName(), other.getDisplayName()) && equal(getBusyExecutors(), other.getBusyExecutors())
|
||||||
|
&& equal(getTotalExecutors(), other.getTotalExecutors()) && equal(getComputers(), other.getComputers());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(getDisplayName(), getBusyExecutors(), getTotalExecutors(), getComputers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return string().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ToStringHelper string() {
|
||||||
|
return toStringHelper("").add("displayName", getDisplayName()).add("busyExecutors", getBusyExecutors()).add(
|
||||||
|
"totalExecutors", getTotalExecutors()).add("computers", getComputers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ComputerView that) {
|
||||||
|
if (that == null)
|
||||||
|
return 1;
|
||||||
|
if (this == that)
|
||||||
|
return 0;
|
||||||
|
return this.getDisplayName().compareTo(that.getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.features;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.jenkins.v1.domain.Computer;
|
||||||
|
import org.jclouds.jenkins.v1.domain.ComputerView;
|
||||||
|
import org.jclouds.jenkins.v1.filters.BasicAuthenticationUnlessAnonymous;
|
||||||
|
import org.jclouds.rest.annotations.ExceptionParser;
|
||||||
|
import org.jclouds.rest.annotations.RequestFilters;
|
||||||
|
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computer Services
|
||||||
|
*
|
||||||
|
* @see ComputerClient
|
||||||
|
* @author Adrian Cole
|
||||||
|
* @see <a href=
|
||||||
|
* "http://ci.jruby.org/computer/api/"
|
||||||
|
* >api doc</a>
|
||||||
|
*/
|
||||||
|
@RequestFilters(BasicAuthenticationUnlessAnonymous.class)
|
||||||
|
public interface ComputerAsyncClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ComputerClient#getComputerView
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/computer/api/json")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
ListenableFuture<ComputerView> getComputerView();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ComputerClient#getComputer
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("/computer/{displayName}/api/json")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
|
||||||
|
ListenableFuture<Computer> getComputer(@PathParam("displayName") String displayName);
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.features;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jclouds.concurrent.Timeout;
|
||||||
|
import org.jclouds.jenkins.v1.domain.Computer;
|
||||||
|
import org.jclouds.jenkins.v1.domain.ComputerView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computer Services
|
||||||
|
*
|
||||||
|
* @see ComputerAsyncClient
|
||||||
|
* @author Adrian Cole
|
||||||
|
* @see <a href= "http://ci.jruby.org/computer/api/" >api doc</a>
|
||||||
|
*/
|
||||||
|
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
|
||||||
|
public interface ComputerClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return overview of all configured computers
|
||||||
|
*/
|
||||||
|
ComputerView getComputerView();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param displayName display name of the computer
|
||||||
|
* @return computer or null if not found
|
||||||
|
*/
|
||||||
|
Computer getComputer(String displayName);
|
||||||
|
}
|
|
@ -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.jenkins.v1.filters;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpException;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpRequestFilter;
|
||||||
|
import org.jclouds.http.filters.BasicAuthentication;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsApiMetadata;
|
||||||
|
import org.jclouds.rest.annotations.Identity;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adrian Cole
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class BasicAuthenticationUnlessAnonymous implements HttpRequestFilter {
|
||||||
|
|
||||||
|
private final Optional<BasicAuthentication> auth;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public BasicAuthenticationUnlessAnonymous(@Identity String user, BasicAuthentication auth) {
|
||||||
|
this.auth = JenkinsApiMetadata.ANONYMOUS_IDENTITY.equals(checkNotNull(user, "user")) ? Optional
|
||||||
|
.<BasicAuthentication> absent() : Optional.of(checkNotNull(auth, "auth"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||||
|
if (auth.isPresent())
|
||||||
|
return auth.get().filter(request);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.jenkins.v1.handlers;
|
||||||
|
|
||||||
|
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpCommand;
|
||||||
|
import org.jclouds.http.HttpErrorHandler;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.http.HttpResponseException;
|
||||||
|
import org.jclouds.rest.AuthorizationException;
|
||||||
|
import org.jclouds.rest.ResourceNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will parse and set an appropriate exception on the command object.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// TODO: is there error spec someplace? let's type errors, etc.
|
||||||
|
@Singleton
|
||||||
|
public class JenkinsErrorHandler implements HttpErrorHandler {
|
||||||
|
|
||||||
|
public void handleError(HttpCommand command, HttpResponse response) {
|
||||||
|
// it is important to always read fully and close streams
|
||||||
|
byte[] data = closeClientButKeepContentStream(response);
|
||||||
|
String message = data != null ? new String(data) : null;
|
||||||
|
|
||||||
|
Exception exception = message != null ? new HttpResponseException(command, response, message)
|
||||||
|
: new HttpResponseException(command, response);
|
||||||
|
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
|
||||||
|
response.getStatusLine());
|
||||||
|
switch (response.getStatusCode()) {
|
||||||
|
case 400:
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
case 403:
|
||||||
|
exception = new AuthorizationException(message, exception);
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
|
||||||
|
exception = new ResourceNotFoundException(message, exception);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
command.setException(exception);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.jclouds.jenkins.v1.JenkinsApiMetadata
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1;
|
||||||
|
|
||||||
|
import org.jclouds.View;
|
||||||
|
import org.jclouds.apis.internal.BaseApiMetadataTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "JenkinsApiMetadataTest")
|
||||||
|
public class JenkinsApiMetadataTest extends BaseApiMetadataTest {
|
||||||
|
public JenkinsApiMetadataTest() {
|
||||||
|
super(new JenkinsApiMetadata(), ImmutableSet.<TypeToken<? extends View>> of());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.createMock;
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.EasyMock.replay;
|
||||||
|
import static org.easymock.EasyMock.reportMatcher;
|
||||||
|
import static org.easymock.EasyMock.verify;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.easymock.IArgumentMatcher;
|
||||||
|
import org.jclouds.http.HttpCommand;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.io.Payloads;
|
||||||
|
import org.jclouds.jenkins.v1.handlers.JenkinsErrorHandler;
|
||||||
|
import org.jclouds.rest.ResourceNotFoundException;
|
||||||
|
import org.jclouds.util.Strings2;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "JenkinsErrorHandlerTest")
|
||||||
|
public class JenkinsErrorHandlerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test404WithHTMLDoesntBustParserAndMakesResourceNotFoundException() {
|
||||||
|
assertCodeMakes("GET", URI
|
||||||
|
.create("http://ci.jruby.org/computer/master/api/json"),
|
||||||
|
404, "Not Found", "<html></html>", ResourceNotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content,
|
||||||
|
Class<? extends Exception> expected) {
|
||||||
|
assertCodeMakes(method, uri, statusCode, message, "text/plain", content, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
|
||||||
|
String content, Class<? extends Exception> expected) {
|
||||||
|
|
||||||
|
JenkinsErrorHandler function = new JenkinsErrorHandler();
|
||||||
|
|
||||||
|
HttpCommand command = createMock(HttpCommand.class);
|
||||||
|
HttpRequest request = new HttpRequest(method, uri);
|
||||||
|
HttpResponse response = new HttpResponse(statusCode, message, Payloads.newInputStreamPayload(Strings2
|
||||||
|
.toInputStream(content)));
|
||||||
|
response.getPayload().getContentMetadata().setContentType(contentType);
|
||||||
|
|
||||||
|
expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
|
||||||
|
command.setException(classEq(expected));
|
||||||
|
|
||||||
|
replay(command);
|
||||||
|
|
||||||
|
function.handleError(command, response);
|
||||||
|
|
||||||
|
verify(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Exception classEq(final Class<? extends Exception> in) {
|
||||||
|
reportMatcher(new IArgumentMatcher() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTo(StringBuffer buffer) {
|
||||||
|
buffer.append("classEq(");
|
||||||
|
buffer.append(in);
|
||||||
|
buffer.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Object arg) {
|
||||||
|
return arg.getClass() == in;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.features;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsClient;
|
||||||
|
import org.jclouds.jenkins.v1.internal.BaseJenkinsClientExpectTest;
|
||||||
|
import org.jclouds.jenkins.v1.parse.ParseComputerTest;
|
||||||
|
import org.jclouds.jenkins.v1.parse.ParseComputerViewTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "ComputerClientExpectTest")
|
||||||
|
public class ComputerClientExpectTest extends BaseJenkinsClientExpectTest {
|
||||||
|
|
||||||
|
public void testGetComputerViewWhenResponseIs2xx() {
|
||||||
|
HttpRequest getComputerView = HttpRequest
|
||||||
|
.builder()
|
||||||
|
.method("GET")
|
||||||
|
.endpoint(URI.create("http://localhost:8080/computer/api/json"))
|
||||||
|
.headers(
|
||||||
|
ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
|
||||||
|
.put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build();
|
||||||
|
|
||||||
|
HttpResponse getComputerViewResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/computerview.json")).build();
|
||||||
|
|
||||||
|
JenkinsClient clientWhenServersExist = requestSendsResponse(getComputerView, getComputerViewResponse);
|
||||||
|
|
||||||
|
assertEquals(clientWhenServersExist.getComputerClient().getComputerView().toString(),
|
||||||
|
new ParseComputerViewTest().expected().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetComputerWhenResponseIs2xx() {
|
||||||
|
HttpRequest getComputer = HttpRequest
|
||||||
|
.builder()
|
||||||
|
.method("GET")
|
||||||
|
.endpoint(URI.create("http://localhost:8080/computer/Ruboto/api/json"))
|
||||||
|
.headers(
|
||||||
|
ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
|
||||||
|
.put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build();
|
||||||
|
|
||||||
|
HttpResponse getComputerResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/computer.json")).build();
|
||||||
|
|
||||||
|
JenkinsClient clientWhenServersExist = requestSendsResponse(getComputer, getComputerResponse);
|
||||||
|
|
||||||
|
assertEquals(clientWhenServersExist.getComputerClient().getComputer("Ruboto").toString(),
|
||||||
|
new ParseComputerTest().expected().toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.features;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import org.jclouds.jenkins.v1.domain.Computer;
|
||||||
|
import org.jclouds.jenkins.v1.domain.ComputerView;
|
||||||
|
import org.jclouds.jenkins.v1.internal.BaseJenkinsClientLiveTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "live", testName = "ComputerClientLiveTest")
|
||||||
|
public class ComputerClientLiveTest extends BaseJenkinsClientLiveTest {
|
||||||
|
|
||||||
|
public void testGetComputerView(){
|
||||||
|
ComputerView view = getClient().getComputerView();
|
||||||
|
assertNotNull(view);
|
||||||
|
assertNotNull(view.getDisplayName());
|
||||||
|
for (Computer computerFromView : view.getComputers()) {
|
||||||
|
assertNotNull(computerFromView.getDisplayName());
|
||||||
|
if (!"master".equals(computerFromView.getDisplayName())) {
|
||||||
|
Computer computerFromGetRequest = getClient().getComputer(computerFromView.getDisplayName());
|
||||||
|
assertEquals(computerFromGetRequest, computerFromView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComputerClient getClient() {
|
||||||
|
return context.getApi().getComputerClient();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.filters;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsApiMetadata;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsClient;
|
||||||
|
import org.jclouds.jenkins.v1.internal.BaseJenkinsClientExpectTest;
|
||||||
|
import org.jclouds.jenkins.v1.parse.ParseComputerViewTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "BasicAuthenticationUnlessAnonymousExpectTest")
|
||||||
|
public class BasicAuthenticationUnlessAnonymousExpectTest extends BaseJenkinsClientExpectTest {
|
||||||
|
|
||||||
|
public BasicAuthenticationUnlessAnonymousExpectTest(){
|
||||||
|
identity = JenkinsApiMetadata.ANONYMOUS_IDENTITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWhenIdentityIsAnonymousNoAuthorizationHeader() {
|
||||||
|
HttpRequest getComputerView = HttpRequest
|
||||||
|
.builder()
|
||||||
|
.method("GET")
|
||||||
|
.endpoint(URI.create("http://localhost:8080/computer/api/json"))
|
||||||
|
.headers(
|
||||||
|
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").build()).build();
|
||||||
|
|
||||||
|
HttpResponse getComputerViewResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/computerview.json")).build();
|
||||||
|
|
||||||
|
JenkinsClient clientWhenServersExist = requestSendsResponse(getComputerView, getComputerViewResponse);
|
||||||
|
|
||||||
|
assertEquals(clientWhenServersExist.getComputerClient().getComputerView().toString(),
|
||||||
|
new ParseComputerViewTest().expected().toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.internal;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsAsyncClient;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for writing KeyStone Rest Client Expect tests
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class BaseJenkinsAsyncClientExpectTest extends BaseJenkinsExpectTest<JenkinsAsyncClient> {
|
||||||
|
public JenkinsAsyncClient createClient(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
|
||||||
|
return createInjector(fn, module, props).getInstance(JenkinsAsyncClient.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.internal;
|
||||||
|
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for writing Jenkins Expect tests
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class BaseJenkinsClientExpectTest extends BaseJenkinsExpectTest<JenkinsClient> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.internal;
|
||||||
|
|
||||||
|
import org.jclouds.apis.BaseContextLiveTest;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsApiMetadata;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsAsyncClient;
|
||||||
|
import org.jclouds.jenkins.v1.JenkinsClient;
|
||||||
|
import org.jclouds.rest.RestContext;
|
||||||
|
import org.testng.annotations.AfterGroups;
|
||||||
|
import org.testng.annotations.BeforeGroups;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of {@code JenkinsClient}
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "live")
|
||||||
|
public class BaseJenkinsClientLiveTest extends BaseContextLiveTest<RestContext<JenkinsClient, JenkinsAsyncClient>> {
|
||||||
|
|
||||||
|
public BaseJenkinsClientLiveTest() {
|
||||||
|
provider = "jenkins";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RestContext<JenkinsClient, JenkinsAsyncClient> jenkinsContext;
|
||||||
|
|
||||||
|
@BeforeGroups(groups = { "integration", "live" })
|
||||||
|
@Override
|
||||||
|
public void setupContext() {
|
||||||
|
super.setupContext();
|
||||||
|
jenkinsContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterGroups(groups = "live")
|
||||||
|
protected void tearDown() {
|
||||||
|
if (jenkinsContext != null)
|
||||||
|
jenkinsContext.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TypeToken<RestContext<JenkinsClient, JenkinsAsyncClient>> contextType() {
|
||||||
|
return JenkinsApiMetadata.CONTEXT_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.internal;
|
||||||
|
|
||||||
|
import org.jclouds.rest.internal.BaseRestClientExpectTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for writing Jenkins Expect tests
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class BaseJenkinsExpectTest<T> extends BaseRestClientExpectTest<T> {
|
||||||
|
public BaseJenkinsExpectTest() {
|
||||||
|
provider = "jenkins";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.parse;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.jenkins.v1.domain.Computer;
|
||||||
|
import org.jclouds.json.BaseItemParserTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "ParseComputerTest")
|
||||||
|
public class ParseComputerTest extends BaseItemParserTest<Computer> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resource() {
|
||||||
|
return "/computer.json";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public Computer expected() {
|
||||||
|
return Computer.builder()
|
||||||
|
.displayName("Ruboto")
|
||||||
|
.idle(true)
|
||||||
|
.offline(false)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* 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.jenkins.v1.parse;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jclouds.jenkins.v1.domain.Computer;
|
||||||
|
import org.jclouds.jenkins.v1.domain.ComputerView;
|
||||||
|
import org.jclouds.json.BaseItemParserTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "ParseComputerViewTest")
|
||||||
|
public class ParseComputerViewTest extends BaseItemParserTest<ComputerView> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resource() {
|
||||||
|
return "/computerview.json";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public ComputerView expected() {
|
||||||
|
return ComputerView.builder()
|
||||||
|
.displayName("nodes")
|
||||||
|
.totalExecutors(4)
|
||||||
|
.busyExecutors(0)
|
||||||
|
.computers(ImmutableSet.<Computer>builder()
|
||||||
|
.add(Computer.builder()
|
||||||
|
.displayName("master")
|
||||||
|
.idle(true)
|
||||||
|
.offline(false).build())
|
||||||
|
.add(Computer.builder()
|
||||||
|
.displayName("Ruboto")
|
||||||
|
.idle(true)
|
||||||
|
.offline(false).build())
|
||||||
|
.add(Computer.builder()
|
||||||
|
.displayName("winserver2008-x86")
|
||||||
|
.idle(true)
|
||||||
|
.offline(false).build()).build()).build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"displayName": "Ruboto",
|
||||||
|
"executors": [{}],
|
||||||
|
"icon": "computer.png",
|
||||||
|
"idle": true,
|
||||||
|
"jnlpAgent": true,
|
||||||
|
"launchSupported": false,
|
||||||
|
"loadStatistics": {},
|
||||||
|
"manualLaunchAllowed": true,
|
||||||
|
"monitorData": {
|
||||||
|
"hudson.node_monitors.SwapSpaceMonitor": {
|
||||||
|
"availablePhysicalMemory": 1697591296,
|
||||||
|
"availableSwapSpace": 5626036224,
|
||||||
|
"totalPhysicalMemory": 4157317120,
|
||||||
|
"totalSwapSpace": 6568271872
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ArchitectureMonitor": "Linux (amd64)",
|
||||||
|
"hudson.node_monitors.ResponseTimeMonitor": {
|
||||||
|
"average": 955
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.TemporarySpaceMonitor": {
|
||||||
|
"size": 53646782464
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.DiskSpaceMonitor": {
|
||||||
|
"size": 53646782464
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ClockMonitor": {
|
||||||
|
"diff": -309
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"numExecutors": 1,
|
||||||
|
"offline": false,
|
||||||
|
"offlineCause": null,
|
||||||
|
"oneOffExecutors": [],
|
||||||
|
"temporarilyOffline": false
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
{
|
||||||
|
"busyExecutors": 0,
|
||||||
|
"computer": [{
|
||||||
|
"actions": [],
|
||||||
|
"displayName": "master",
|
||||||
|
"executors": [{}, {}],
|
||||||
|
"icon": "computer.png",
|
||||||
|
"idle": true,
|
||||||
|
"jnlpAgent": false,
|
||||||
|
"launchSupported": true,
|
||||||
|
"loadStatistics": {},
|
||||||
|
"manualLaunchAllowed": true,
|
||||||
|
"monitorData": {
|
||||||
|
"hudson.node_monitors.SwapSpaceMonitor": {
|
||||||
|
"availablePhysicalMemory": 1385115648,
|
||||||
|
"availableSwapSpace": 32208396288,
|
||||||
|
"totalPhysicalMemory": 8053207040,
|
||||||
|
"totalSwapSpace": 32218378240
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ArchitectureMonitor": "Linux (amd64)",
|
||||||
|
"hudson.node_monitors.ResponseTimeMonitor": {
|
||||||
|
"average": 1
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.TemporarySpaceMonitor": {
|
||||||
|
"size": 6235500544
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.DiskSpaceMonitor": {
|
||||||
|
"size": 79292284928
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ClockMonitor": {
|
||||||
|
"diff": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"numExecutors": 2,
|
||||||
|
"offline": false,
|
||||||
|
"offlineCause": null,
|
||||||
|
"oneOffExecutors": [],
|
||||||
|
"temporarilyOffline": false
|
||||||
|
}, {
|
||||||
|
"actions": [],
|
||||||
|
"displayName": "Ruboto",
|
||||||
|
"executors": [{}],
|
||||||
|
"icon": "computer.png",
|
||||||
|
"idle": true,
|
||||||
|
"jnlpAgent": true,
|
||||||
|
"launchSupported": false,
|
||||||
|
"loadStatistics": {},
|
||||||
|
"manualLaunchAllowed": true,
|
||||||
|
"monitorData": {
|
||||||
|
"hudson.node_monitors.SwapSpaceMonitor": {
|
||||||
|
"availablePhysicalMemory": 1684832256,
|
||||||
|
"availableSwapSpace": 5625421824,
|
||||||
|
"totalPhysicalMemory": 4157317120,
|
||||||
|
"totalSwapSpace": 6568271872
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ArchitectureMonitor": "Linux (amd64)",
|
||||||
|
"hudson.node_monitors.ResponseTimeMonitor": {
|
||||||
|
"average": 856
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.TemporarySpaceMonitor": {
|
||||||
|
"size": 53648973824
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.DiskSpaceMonitor": {
|
||||||
|
"size": 53648969728
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ClockMonitor": {
|
||||||
|
"diff": -462
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"numExecutors": 1,
|
||||||
|
"offline": false,
|
||||||
|
"offlineCause": null,
|
||||||
|
"oneOffExecutors": [],
|
||||||
|
"temporarilyOffline": false
|
||||||
|
}, {
|
||||||
|
"actions": [],
|
||||||
|
"displayName": "winserver2008-x86",
|
||||||
|
"executors": [{}],
|
||||||
|
"icon": "computer.png",
|
||||||
|
"idle": true,
|
||||||
|
"jnlpAgent": true,
|
||||||
|
"launchSupported": false,
|
||||||
|
"loadStatistics": {},
|
||||||
|
"manualLaunchAllowed": true,
|
||||||
|
"monitorData": {
|
||||||
|
"hudson.node_monitors.SwapSpaceMonitor": {
|
||||||
|
"availablePhysicalMemory": 1117851648,
|
||||||
|
"availableSwapSpace": 1429299200,
|
||||||
|
"totalPhysicalMemory": 1781420032,
|
||||||
|
"totalSwapSpace": 1994350592
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ArchitectureMonitor": "Windows Server 2008 (x86)",
|
||||||
|
"hudson.node_monitors.ResponseTimeMonitor": {
|
||||||
|
"average": 1
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.TemporarySpaceMonitor": {
|
||||||
|
"size": 19072663552
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.DiskSpaceMonitor": {
|
||||||
|
"size": 19072663552
|
||||||
|
},
|
||||||
|
"hudson.node_monitors.ClockMonitor": {
|
||||||
|
"diff": 71
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"numExecutors": 1,
|
||||||
|
"offline": false,
|
||||||
|
"offlineCause": null,
|
||||||
|
"oneOffExecutors": [],
|
||||||
|
"temporarilyOffline": false
|
||||||
|
}],
|
||||||
|
"displayName": "nodes",
|
||||||
|
"totalExecutors": 4
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<configuration scan="false">
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<file>target/test-data/jclouds.log</file>
|
||||||
|
|
||||||
|
<encoder>
|
||||||
|
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="WIREFILE" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<file>target/test-data/jclouds-wire.log</file>
|
||||||
|
|
||||||
|
<encoder>
|
||||||
|
<Pattern>%d %-5p [%c] [%thread] %m%n</Pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root>
|
||||||
|
<level value="warn" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
<logger name="org.jclouds">
|
||||||
|
<level value="DEBUG" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="jclouds.wire">
|
||||||
|
<level value="DEBUG" />
|
||||||
|
<appender-ref ref="WIREFILE" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="jclouds.headers">
|
||||||
|
<level value="DEBUG" />
|
||||||
|
<appender-ref ref="WIREFILE" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
</configuration>
|
|
@ -42,5 +42,6 @@
|
||||||
<module>dmtf</module>
|
<module>dmtf</module>
|
||||||
<module>carrenza-vcloud-director</module>
|
<module>carrenza-vcloud-director</module>
|
||||||
<module>openstack-swift</module>
|
<module>openstack-swift</module>
|
||||||
|
<module>jenkins</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* 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.hpcloud.compute.features;
|
||||||
|
|
||||||
|
import org.jclouds.openstack.nova.v1_1.extensions.VolumeClientLiveTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "live", testName = "HPCloudComputeVolumeClientLiveTest")
|
||||||
|
public class HPCloudComputeVolumeClientLiveTest extends VolumeClientLiveTest {
|
||||||
|
public HPCloudComputeVolumeClientLiveTest() {
|
||||||
|
provider = "hpcloud-compute";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue