Merge pull request #608 from aplowe/openstack-nova

Openstack nova: Adding AdminActions, VirtualInterfaces and ServerWithSecurityGroup extensions
This commit is contained in:
Adrian Cole 2012-05-04 13:45:16 -07:00
commit 103a95f22b
34 changed files with 2719 additions and 586 deletions

View File

@ -23,11 +23,14 @@ import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Zone;
import org.jclouds.location.functions.ZoneToEndpoint;
import org.jclouds.openstack.nova.v1_1.extensions.AdminActionsAsyncClient;
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPAsyncClient;
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.SecurityGroupAsyncClient;
import org.jclouds.openstack.nova.v1_1.extensions.ServerWithSecurityGroupsAsyncClient;
import org.jclouds.openstack.nova.v1_1.extensions.SimpleTenantUsageAsyncClient;
import org.jclouds.openstack.nova.v1_1.extensions.VirtualInterfaceAsyncClient;
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.FlavorAsyncClient;
@ -127,4 +130,27 @@ public interface NovaAsyncClient {
@Delegate
Optional<VolumeAsyncClient> getVolumeExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides asynchronous access to Virtual Interface features.
*/
@Delegate
Optional<VirtualInterfaceAsyncClient> getVirtualInterfaceExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides asynchronous access to Server Extra Data features.
*/
@Delegate
Optional<ServerWithSecurityGroupsAsyncClient> getServerWithSecurityGroupsExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides asynchronous access to Server Admin Actions features.
*/
@Delegate
Optional<AdminActionsAsyncClient> getAdminActionsExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
}

View File

@ -25,11 +25,14 @@ import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Zone;
import org.jclouds.location.functions.ZoneToEndpoint;
import org.jclouds.openstack.nova.v1_1.extensions.AdminActionsClient;
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient;
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.SecurityGroupClient;
import org.jclouds.openstack.nova.v1_1.extensions.ServerWithSecurityGroupsClient;
import org.jclouds.openstack.nova.v1_1.extensions.SimpleTenantUsageClient;
import org.jclouds.openstack.nova.v1_1.extensions.VirtualInterfaceClient;
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.FlavorClient;
@ -123,7 +126,6 @@ public interface NovaClient {
Optional<SimpleTenantUsageClient> getSimpleTenantUsageExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides synchronous access to Volume features.
*/
@ -131,4 +133,25 @@ public interface NovaClient {
Optional<VolumeClient> getVolumeExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides synchronous access to Virtual Interface features.
*/
@Delegate
Optional<VirtualInterfaceClient> getVirtualInterfaceExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides synchronous access to Server Extra Data features.
*/
@Delegate
Optional<ServerWithSecurityGroupsClient> getServerWithSecurityGroupsExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
/**
* Provides synchronous access to Server Admin Actions features.
*/
@Delegate
Optional<AdminActionsClient> getAdminActionsExtensionForZone(
@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
}

View File

@ -219,12 +219,20 @@ public class NovaComputeServiceAdapter implements
@Override
public void resumeNode(String id) {
throw new UnsupportedOperationException("suspend not supported");
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
if (novaClient.getAdminActionsExtensionForZone(zoneAndId.getZone()).isPresent()) {
novaClient.getAdminActionsExtensionForZone(zoneAndId.getZone()).get().resumeServer(zoneAndId.getId());
}
throw new UnsupportedOperationException("resume requires installation of the Admin Actions extension");
}
@Override
public void suspendNode(String id) {
throw new UnsupportedOperationException("suspend not supported");
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
if (novaClient.getAdminActionsExtensionForZone(zoneAndId.getZone()).isPresent()) {
novaClient.getAdminActionsExtensionForZone(zoneAndId.getZone()).get().suspendServer(zoneAndId.getId());
}
throw new UnsupportedOperationException("suspend requires installation of the Admin Actions extension");
}
}

View File

@ -20,14 +20,19 @@ package org.jclouds.openstack.nova.v1_1.config;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
import javax.inject.Singleton;
import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.openstack.nova.v1_1.domain.HostResourceUsage;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.ServerWithSecurityGroups;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
@ -39,13 +44,17 @@ import com.google.inject.Provides;
/**
* @author Adrian Cole
* @author Adam Lowe
*/
public class NovaParserModule extends AbstractModule {
@Provides
@Singleton
public Map<Type, Object> provideCustomAdapterBindings() {
return ImmutableMap.<Type, Object> of(HostResourceUsage.class, new HostResourceUsageAdapter());
return ImmutableMap.<Type, Object> of(
HostResourceUsage.class, new HostResourceUsageAdapter(),
ServerWithSecurityGroups.class, new ServerWithSecurityGroupsAdapter()
);
}
@Override
@ -79,4 +88,22 @@ public class NovaParserModule extends AbstractModule {
}
}
@Singleton
public static class ServerWithSecurityGroupsAdapter implements JsonDeserializer<ServerWithSecurityGroups> {
@Override
public ServerWithSecurityGroups deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context)
throws JsonParseException {
Server server = context.deserialize(jsonElement, Server.class);
ServerWithSecurityGroups.Builder result = ServerWithSecurityGroups.builder().fromServer(server);
Set<String> names = Sets.newLinkedHashSet();
if (jsonElement.getAsJsonObject().get("security_groups") != null) {
JsonArray x = jsonElement.getAsJsonObject().get("security_groups").getAsJsonArray();
for(JsonElement y : x) {
names.add(y.getAsJsonObject().get("name").getAsString());
}
result.securityGroupNames(names);
}
return result.build();
}
}
}

View File

@ -74,6 +74,9 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
.put(HostAdministrationClient.class, HostAdministrationAsyncClient.class)
.put(SimpleTenantUsageClient.class, SimpleTenantUsageAsyncClient.class)
.put(VolumeClient.class, VolumeAsyncClient.class)
.put(VirtualInterfaceClient.class, VirtualInterfaceAsyncClient.class)
.put(ServerWithSecurityGroupsClient.class, ServerWithSecurityGroupsAsyncClient.class)
.put(AdminActionsClient.class, AdminActionsAsyncClient.class)
.build();
public NovaRestClientModule() {

View File

@ -0,0 +1,43 @@
/**
* 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 com.google.common.base.CaseFormat;
/**
* @author Adam Lowe
*/
public enum BackupType {
DAILY, WEEKLY;
public String value() {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name());
}
@Override
public String toString() {
return value();
}
public static BackupType fromValue(String backupType) {
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(backupType, "backupType")));
}
}

View File

@ -18,15 +18,13 @@
*/
package org.jclouds.openstack.nova.v1_1.domain;
import static com.google.common.base.Objects.toStringHelper;
import java.net.URI;
import java.util.Date;
import java.util.Set;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import com.google.common.base.Objects;
/**
* The OpenStack Compute API is extensible. Extensions serve two purposes: They
* allow the introduction of new features in the API without requiring a version
@ -39,94 +37,86 @@ import org.jclouds.openstack.domain.Resource;
* />
*/
public class Extension extends Resource {
public static Builder builder() {
return new Builder();
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder toBuilder() {
return builder().fromExtension(this);
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromExtension(this);
}
public static class Builder extends Resource.Builder {
public static abstract class Builder<T extends Builder<T>> extends Resource.Builder<T> {
private URI namespace;
private String alias;
private Date updated;
private String description;
public Builder namespace(URI namespace) {
/**
* @see Extension#getNamespace()
*/
public T namespace(URI namespace) {
this.namespace = namespace;
return this;
return self();
}
public Builder alias(String alias) {
/**
* @see Extension#getAlias()
*/
public T alias(String alias) {
id(alias);
this.alias = alias;
return this;
return self();
}
public Builder updated(Date updated) {
/**
* @see Extension#getUpdated()
*/
public T updated(Date updated) {
this.updated = updated;
return this;
return self();
}
public Builder description(String description) {
/**
* @see Extension#getDescription()
*/
public T description(String description) {
this.description = description;
return this;
return self();
}
public Extension build() {
return new Extension(name, links, namespace, alias, updated, description);
return new Extension(this);
}
public Builder fromExtension(Extension in) {
return fromResource(in).namespace(in.getNamespace()).alias(in.getAlias()).updated(in.getUpdated())
.description(in.getDescription());
public T fromExtension(Extension in) {
return super.fromResource(in)
.namespace(in.getNamespace())
.alias(in.getAlias())
.updated(in.getUpdated())
.description(in.getDescription())
;
}
/**
* {@inheritDoc}
*/
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
public Builder id(String id) {
return alias(id);
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Set<Link> links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromResource(Resource in) {
return Builder.class.cast(super.fromResource(in));
protected ConcreteBuilder self() {
return this;
}
}
private URI namespace;
private String alias;
private Date updated;
private String description;
private final URI namespace;
private final String alias;
private final Date updated;
private final String description;
protected Extension(String name, Set<Link> links, URI namespace, String alias, Date updated, String description) {
super(alias, name, links);
this.namespace = namespace;
this.alias = alias;
this.updated = updated;
this.description = description;
protected Extension(Builder<?> builder) {
super(builder);
this.namespace = builder.namespace;
this.alias = builder.alias;
this.updated = builder.updated;
this.description = builder.description;
}
public URI getNamespace() {
@ -151,9 +141,11 @@ public class Extension extends Resource {
}
@Override
public String toString() {
return toStringHelper("").add("id", getId()).add("name", name).add("links", links).add("namespace", namespace)
.add("alias", alias).add("updated", updated).add("description", description).toString();
public Objects.ToStringHelper string() {
return super.string()
.add("namespace", namespace)
.add("alias", alias)
.add("updated", updated)
.add("description", description);
}
}

View File

@ -18,13 +18,10 @@
*/
package org.jclouds.openstack.nova.v1_1.domain;
import static com.google.common.base.Objects.toStringHelper;
import java.util.Set;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import com.google.common.base.Objects;
/**
* A flavor is an available hardware configuration for a server. Each flavor has
* a unique combination of disk space and memory capacity.
@ -35,73 +32,61 @@ import org.jclouds.openstack.domain.Resource;
* />
*/
public class Flavor extends Resource {
public static Builder builder() {
return new Builder();
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder toBuilder() {
return builder().fromFlavor(this);
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromFlavor(this);
}
public static class Builder extends Resource.Builder {
public static abstract class Builder<T extends Builder<T>> extends Resource.Builder<T> {
private int ram;
private int disk;
private int vcpus;
public Builder ram(int ram) {
/**
* @see Flavor#getRam()
*/
public T ram(int ram) {
this.ram = ram;
return this;
return self();
}
public Builder disk(int disk) {
/**
* @see Flavor#getDisk()
*/
public T disk(int disk) {
this.disk = disk;
return this;
return self();
}
public Builder vcpus(int vcpus) {
/**
* @see Flavor#getVcpus()
*/
public T vcpus(int vcpus) {
this.vcpus = vcpus;
return this;
return self();
}
public Flavor build() {
return new Flavor(id, name, links, ram, disk, vcpus);
return new Flavor(this);
}
public Builder fromFlavor(Flavor in) {
return fromResource(in).ram(in.getRam()).disk(in.getDisk()).vcpus(in.getVcpus());
public T fromFlavor(Flavor in) {
return super.fromResource(in)
.ram(in.getRam())
.disk(in.getDisk())
.vcpus(in.getVcpus())
;
}
/**
* {@inheritDoc}
*/
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
public Builder id(String id) {
return Builder.class.cast(super.id(id));
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Set<Link> links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromResource(Resource in) {
return Builder.class.cast(super.fromResource(in));
protected ConcreteBuilder self() {
return this;
}
}
@ -109,11 +94,11 @@ public class Flavor extends Resource {
private int disk;
private int vcpus;
protected Flavor(String id, String name, Set<Link> links, int ram, int disk, int vcpus) {
super(id, name, links);
this.ram = ram;
this.disk = disk;
this.vcpus = vcpus;
protected Flavor(Builder<?> builder) {
super(builder);
this.ram = builder.ram;
this.disk = builder.disk;
this.vcpus = builder.vcpus;
}
public int getRam() {
@ -129,9 +114,10 @@ public class Flavor extends Resource {
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("name", name).add("links", links).add("ram", ram).add("disk", disk)
.add("vcpus", vcpus).toString();
protected Objects.ToStringHelper string() {
return super.string()
.add("ram", ram)
.add("disk", disk)
.add("vcpus", vcpus);
}
}

View File

@ -18,15 +18,12 @@
*/
package org.jclouds.openstack.nova.v1_1.domain;
import static com.google.common.base.Objects.toStringHelper;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import com.google.common.base.Objects;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@ -68,117 +65,130 @@ public class Image extends Resource {
}
public static Builder builder() {
return new Builder();
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder toBuilder() {
return builder().fromImage(this);
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromImage(this);
}
public static class Builder extends Resource.Builder {
public static abstract class Builder<T extends Builder<T>> extends Resource.Builder<T> {
private Date updated;
private Date created;
private String tenantId;
private String userId;
private Status status;
private Image.Status status;
private int progress;
private int minDisk;
private int minRam;
private Resource server;
private Map<String, String> metadata = Maps.newLinkedHashMap();
private Map<String, String> metadata = ImmutableMap.of();
public Builder updated(Date updated) {
/**
* @see Image#getUpdated()
*/
public T updated(Date updated) {
this.updated = updated;
return this;
return self();
}
public Builder created(Date created) {
/**
* @see Image#getCreated()
*/
public T created(Date created) {
this.created = created;
return this;
return self();
}
public Builder tenantId(String tenantId) {
/**
* @see Image#getTenantId()
*/
public T tenantId(String tenantId) {
this.tenantId = tenantId;
return this;
return self();
}
public Builder userId(String userId) {
/**
* @see Image#getUserId()
*/
public T userId(String userId) {
this.userId = userId;
return this;
return self();
}
public Builder status(Status status) {
/**
* @see Image#getStatus()
*/
public T status(Image.Status status) {
this.status = status;
return this;
return self();
}
public Builder progress(int progress) {
/**
* @see Image#getProgress()
*/
public T progress(int progress) {
this.progress = progress;
return this;
return self();
}
public Builder minDisk(int minDisk) {
/**
* @see Image#getMinDisk()
*/
public T minDisk(int minDisk) {
this.minDisk = minDisk;
return this;
return self();
}
public Builder minRam(int minRam) {
/**
* @see Image#getMinRam()
*/
public T minRam(int minRam) {
this.minRam = minRam;
return this;
return self();
}
public Builder server(Resource server) {
/**
* @see Image#getServer()
*/
public T server(Resource server) {
this.server = server;
return this;
return self();
}
public Builder metadata(Map<String, String> metadata) {
/**
* @see Image#getMetadata()
*/
public T metadata(Map<String, String> metadata) {
this.metadata = metadata;
return this;
return self();
}
public Image build() {
return new Image(id, name, links, updated, created, tenantId, userId, status, progress, minDisk, minRam,
server, metadata);
return new Image(this);
}
public Builder fromImage(Image in) {
return fromResource(in).status(in.getStatus()).updated(in.getUpdated()).created(in.getCreated()).progress(
in.getProgress()).server(in.getServer()).metadata(in.getMetadata());
public T fromImage(Image in) {
return super.fromResource(in)
.updated(in.getUpdated())
.created(in.getCreated())
.tenantId(in.getTenantId())
.userId(in.getUserId())
.status(in.getStatus())
.progress(in.getProgress())
.minDisk(in.getMinDisk())
.minRam(in.getMinRam())
.server(in.getServer())
.metadata(in.getMetadata());
}
/**
* {@inheritDoc}
*/
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
public Builder id(String id) {
return Builder.class.cast(super.id(id));
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Set<Link> links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromResource(Resource in) {
return Builder.class.cast(super.fromResource(in));
protected ConcreteBuilder self() {
return this;
}
}
@ -195,19 +205,18 @@ public class Image extends Resource {
private final Resource server;
private final Map<String, String> metadata;
protected Image(String id, String name, Set<Link> links, Date updated, Date created, String tenantId, String userId,
Status status, int progress, int minDisk, int minRam, Resource server, Map<String, String> metadata) {
super(id, name, links);
this.updated = updated;
this.created = created;
this.tenantId = tenantId;
this.userId = userId;
this.status = status;
this.progress = progress;
this.minDisk = minDisk;
this.minRam = minRam;
this.server = server;
this.metadata = ImmutableMap.<String, String> copyOf(metadata);
protected Image(Builder<?> builder) {
super(builder);
this.updated = builder.updated;
this.created = builder.created;
this.tenantId = builder.tenantId;
this.userId = builder.userId;
this.status = builder.status;
this.progress = builder.progress;
this.minDisk = builder.minDisk;
this.minRam = builder.minRam;
this.server = builder.server;
this.metadata = ImmutableMap.copyOf(builder.metadata);
}
public Date getUpdated() {
@ -252,11 +261,18 @@ public class Image extends Resource {
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("name", name).add("links", links).add("updated", updated).add(
"created", created).add("tenantId", tenantId).add("userId", userId).add("status", status).add(
"progress", progress).add("minDisk", minDisk).add("minRam", minRam).add("server", server).add(
"metadata", metadata).toString();
protected Objects.ToStringHelper string() {
return super.string()
.add("updated", updated)
.add("created", created)
.add("tenantId", tenantId)
.add("userId", userId)
.add("status", status)
.add("progress", progress)
.add("minDisk", minDisk)
.add("minRam", minRam)
.add("server", server)
.add("metadata", metadata);
}
}

View File

@ -26,7 +26,6 @@ import java.util.Set;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
import org.jclouds.util.Multimaps2;
@ -36,7 +35,6 @@ import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.gson.annotations.SerializedName;
@ -67,7 +65,7 @@ public class Server extends Resource {
NodeState.PENDING), VERIFY_RESIZE(NodeState.PENDING), REVERT_RESIZE(NodeState.PENDING), PASSWORD(
NodeState.PENDING), REBOOT(NodeState.PENDING), HARD_REBOOT(NodeState.PENDING), DELETED(
NodeState.TERMINATED), UNKNOWN(NodeState.UNRECOGNIZED), ERROR(NodeState.ERROR), UNRECOGNIZED(
NodeState.UNRECOGNIZED);
NodeState.UNRECOGNIZED), PAUSED(NodeState.SUSPENDED);
private final NodeState nodeState;
@ -92,15 +90,16 @@ public class Server extends Resource {
}
}
public static Builder builder() {
return new Builder();
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder toBuilder() {
return builder().fromServer(this);
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromServer(this);
}
public static class Builder extends Resource.Builder {
public static abstract class Builder<T extends Builder<T>> extends Resource.Builder<T> {
private String uuid;
private String tenantId;
private String userId;
@ -109,196 +108,242 @@ public class Server extends Resource {
private String hostId;
private String accessIPv4;
private String accessIPv6;
private Status status;
private String configDrive;
private Server.Status status;
private Resource image;
private Resource flavor;
private Map<String, String> metadata = Maps.newHashMap();
// TODO: get gson multimap ad
private Multimap<String, Address> addresses = LinkedHashMultimap.create();
private String adminPass;
private String keyName;
private String configDrive;
private Multimap<String, Address> addresses = ImmutableMultimap.of();
private Map<String, String> metadata = ImmutableMap.of();
private String taskState;
private String vmState;
private String powerState;
private String instanceName;
private String hostName;
private String hypervisorName;
private String diskConfig;
/**
* @see Server#getUuid()
*/
public Builder uuid(@Nullable String uuid) {
public T uuid(String uuid) {
this.uuid = uuid;
return this;
return self();
}
/**
* @see Server#getTenantId()
*/
public Builder tenantId(String tenantId) {
public T tenantId(String tenantId) {
this.tenantId = tenantId;
return this;
return self();
}
/**
* @see Server#getUserId()
*/
public Builder userId(String userId) {
public T userId(String userId) {
this.userId = userId;
return this;
return self();
}
/**
* @see Server#getUpdated()
*/
public Builder updated(Date updated) {
public T updated(Date updated) {
this.updated = updated;
return this;
return self();
}
/**
* @see Server#getCreated()
*/
public Builder created(Date created) {
public T created(Date created) {
this.created = created;
return this;
return self();
}
/**
* @see Server#getHostId()
*/
public Builder hostId(@Nullable String hostId) {
public T hostId(String hostId) {
this.hostId = hostId;
return this;
return self();
}
/**
* @see Server#getAccessIPv4()
*/
public Builder accessIPv4(@Nullable String accessIPv4) {
public T accessIPv4(String accessIPv4) {
this.accessIPv4 = accessIPv4;
return this;
return self();
}
/**
* @see Server#getAccessIPv6()
*/
public Builder accessIPv6(@Nullable String accessIPv6) {
public T accessIPv6(String accessIPv6) {
this.accessIPv6 = accessIPv6;
return this;
return self();
}
/**
* @see Server#getStatus()
*/
public Builder status(Status status) {
public T status(Server.Status status) {
this.status = status;
return this;
}
/**
* @see Server#getConfigDrive()
*/
public Builder configDrive(@Nullable String configDrive) {
this.configDrive = configDrive;
return this;
return self();
}
/**
* @see Server#getImage()
*/
public Builder image(Resource image) {
public T image(Resource image) {
this.image = image;
return this;
return self();
}
/**
* @see Server#getImage()
* @see Server#getFlavor()
*/
public Builder flavor(Resource flavor) {
public T flavor(Resource flavor) {
this.flavor = flavor;
return this;
}
/**
* @see Server#getMetadata()
*/
public Builder metadata(Map<String, String> metadata) {
this.metadata = ImmutableMap.copyOf(metadata);
return this;
}
/**
* @see Server#getAddresses()
*/
public Builder addresses(Multimap<String, Address> addresses) {
this.addresses = ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses"));
return this;
return self();
}
/**
* @see Server#getAdminPass()
*/
public Builder adminPass(String adminPass) {
public T adminPass(String adminPass) {
this.adminPass = adminPass;
return this;
return self();
}
/**
* @see Server#getKeyName()
*/
public Builder keyName(@Nullable String keyName) {
public T keyName(String keyName) {
this.keyName = keyName;
return this;
return self();
}
/**
* @see Server#getConfigDrive()
*/
public T configDrive(String configDrive) {
this.configDrive = configDrive;
return self();
}
/**
* @see Server#getAddresses()
*/
public T addresses(Multimap<String, Address> addresses) {
this.addresses = addresses;
return self();
}
/**
* @see Server#getMetadata()
*/
public T metadata(Map<String, String> metadata) {
this.metadata = metadata;
return self();
}
/**
* @see Server#getTaskState()
*/
public T taskState(String taskState) {
this.taskState = taskState;
return self();
}
/**
* @see Server#getVmState()
*/
public T vmState(String vmState) {
this.vmState = vmState;
return self();
}
/**
* @see Server#getPowerState()
*/
public T powerState(String powerState) {
this.powerState = powerState;
return self();
}
/**
* @see Server#getInstanceName()
*/
public T instanceName(String instanceName) {
this.instanceName = instanceName;
return self();
}
/**
* @see Server#getHostName()
*/
public T hostName(String hostName) {
this.hostName = hostName;
return self();
}
/**
* @see Server#getHypervisorName()
*/
public T hypervisorName(String hypervisorName) {
this.hypervisorName = hypervisorName;
return self();
}
/**
* @see Server#getDiskConfig()
*/
public T diskConfig(String diskConfig) {
this.diskConfig = diskConfig;
return self();
}
@Override
public Server build() {
return new Server(id, name, links, uuid, tenantId, userId, updated, created, hostId, accessIPv4, accessIPv6,
status, configDrive, image, flavor, adminPass, keyName, addresses, metadata);
return new Server(this);
}
public Builder fromServer(Server in) {
return fromResource(in).uuid(in.getUuid()).tenantId(in.getTenantId()).userId(in.getUserId()).updated(
in.getUpdated()).created(in.getCreated()).hostId(in.getHostId()).accessIPv4(in.getAccessIPv4())
.accessIPv6(in.getAccessIPv6()).status(in.getStatus()).configDrive(in.getConfigDrive()).image(
in.getImage()).flavor(in.getFlavor()).adminPass(in.getAdminPass()).keyName(in.getKeyName())
.addresses(in.getAddresses()).metadata(in.getMetadata());
public T fromServer(Server in) {
return super.fromResource(in)
.uuid(in.getUuid())
.tenantId(in.getTenantId())
.userId(in.getUserId())
.updated(in.getUpdated())
.created(in.getCreated())
.hostId(in.getHostId())
.accessIPv4(in.getAccessIPv4())
.accessIPv6(in.getAccessIPv6())
.status(in.getStatus())
.image(in.getImage())
.flavor(in.getFlavor())
.adminPass(in.getAdminPass())
.keyName(in.getKeyName())
.configDrive(in.getConfigDrive())
.addresses(in.getAddresses())
.metadata(in.getMetadata())
.taskState(in.getTaskState())
.vmState(in.getVmState())
.powerState(in.getPowerState())
.instanceName(in.getInstanceName())
.hostName(in.getHostName())
.hypervisorName(in.getHypervisorName())
.diskConfig(in.getDiskConfig());
}
}
/**
* {@inheritDoc}
*/
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
public Builder id(String id) {
return Builder.class.cast(super.id(id));
}
/**
* {@inheritDoc}
*/
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Set<Link> links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Link... links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromResource(Resource in) {
return Builder.class.cast(super.fromResource(in));
protected ConcreteBuilder self() {
return this;
}
}
@ -324,28 +369,51 @@ public class Server extends Resource {
protected final Map<String, Set<Address>> addresses;
protected final Map<String, String> metadata;
protected Server(String id, String name, Set<Link> links, @Nullable String uuid, String tenantId, String userId,
Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4,
@Nullable String accessIPv6, Status status, @Nullable String configDrive, Resource image, Resource flavor,
String adminPass, @Nullable String keyName, Multimap<String, Address> addresses,
Map<String, String> metadata) {
super(id, name, links);
this.uuid = uuid; // TODO: see what version this came up in
this.tenantId = checkNotNull(tenantId, "tenantId");
this.userId = checkNotNull(userId, "userId");
this.updated = checkNotNull(updated, "updated");
this.created = checkNotNull(created, "created");
this.hostId = hostId;
this.accessIPv4 = accessIPv4;
this.accessIPv6 = accessIPv6;
this.status = checkNotNull(status, "status");
this.configDrive = configDrive;
this.image = checkNotNull(image, "image");
this.flavor = checkNotNull(flavor, "flavor");
this.metadata = Maps.newHashMap(metadata);
this.addresses = Multimaps2.toOldSchool(ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses")));
this.adminPass = adminPass;
this.keyName = keyName;
// Extended status extension
@SerializedName("OS-EXT-STS:task_state")
protected final String taskState;
@SerializedName("OS-EXT-STS:vm_state")
protected final String vmState;
@SerializedName("OS-EXT-STS:power_state")
protected final String powerState;
// Extended server attributes extension
@SerializedName("OS-EXT-SRV-ATTR:instance_name")
protected final String instanceName;
@SerializedName("OS-EXT-SRV-ATTR:host")
protected final String hostName;
@SerializedName("OS-EXT-SRV-ATTR:hypervisor_hostname")
protected final String hypervisorName;
// Disk Config extension
@SerializedName("OS-DCF:diskConfig")
protected final String diskConfig;
protected Server(Builder<?> builder) {
super(builder);
this.uuid = builder.uuid; // TODO: see what version this came up in
this.tenantId = checkNotNull(builder.tenantId, "tenantId");
this.userId = checkNotNull(builder.userId, "userId");
this.updated = checkNotNull(builder.updated, "updated");
this.created = checkNotNull(builder.created, "created");
this.hostId = builder.hostId;
this.accessIPv4 = builder.accessIPv4;
this.accessIPv6 = builder.accessIPv6;
this.status = checkNotNull(builder.status, "status");
this.configDrive = builder.configDrive;
this.image = checkNotNull(builder.image, "image");
this.flavor = checkNotNull(builder.flavor, "flavor");
this.metadata = Maps.newHashMap(builder.metadata);
this.addresses = Multimaps2.toOldSchool(ImmutableMultimap.copyOf(checkNotNull(builder.addresses, "addresses")));
this.adminPass = builder.adminPass;
this.keyName = builder.keyName;
this.taskState = builder.taskState;
this.vmState = builder.vmState;
this.powerState = builder.powerState;
this.instanceName = builder.instanceName;
this.hostName = builder.hostName;
this.hypervisorName = builder.hypervisorName;
this.diskConfig = builder.diskConfig;
}
/**
@ -375,8 +443,7 @@ public class Server extends Resource {
}
/**
*
* @return host identifier, or null if in {@link ServerState#BUILD}
* @return host identifier, or null if in {@link Status#BUILD}
*/
@Nullable
public String getHostId() {
@ -439,6 +506,79 @@ public class Server extends Resource {
return keyName;
}
/**
* State of task running against this instance (e.g. "suspending")
* <p/>
* NOTE: This field is only present if the Extended Status extension is installed.
*/
@Nullable
public String getTaskState() {
return this.taskState;
}
/**
* State of task running against this instance (e.g. "suspending")
* <p/>
* NOTE: This field is only present if the Extended Status extension is installed.
*/
@Nullable
public String getVmState() {
return this.vmState;
}
/**
* State of task running against this instance (e.g. "suspending")
* <p/>
* NOTE: This field is only present if the Extended Status extension is installed.
*/
@Nullable
public String getPowerState() {
return this.powerState;
}
/**
* The name of the instance?
* <p/>
* NOTE: This field is only present if the The Extended Server Attributes API extension is installed.
*/
@Nullable
public String getInstanceName() {
return this.instanceName;
}
/**
* The host name of the host this Server is running on
* <p/>
* NOTE: This field is only present if the The Extended Server Attributes API extension is installed.
* @see #getHostId()
*/
@Nullable
public String getHostName() {
return this.hostName;
}
/**
* The name of the hypervisor this Server is running on
* <p/>
* NOTE: This field is only present if the The Extended Server Attributes API extension is installed.
*/
@Nullable
public String getHypervisorName() {
return this.hypervisorName;
}
/**
* State of task running against this instance (e.g. "suspending")
* <p/>
* NOTE: This field is only present if the Disk Config extension is installed.
*/
@Nullable
public String getDiskConfig() {
return this.diskConfig;
}
// hashCode/equals from super is ok
@Override

View File

@ -0,0 +1,109 @@
/**
* 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.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;
/**
* Extended server returned by ServerWithSecurityGroupsClient
*
* @author Adam Lowe
* @see <a href=
"http://docs.openstack.org/api/openstack-compute/1.1/content/Get_Server_Details-d1e2623.html"
/>
*/
public class ServerWithSecurityGroups extends Server {
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromServerWithSecurityGroups(this);
}
public static abstract class Builder<T extends Builder<T>> extends Server.Builder<T> {
private Set<String> securityGroupNames = ImmutableSet.of();
/**
* @see ServerWithSecurityGroups#getSecurityGroupNames()
*/
public T securityGroupNames(Set<String> securityGroupNames) {
this.securityGroupNames = securityGroupNames;
return self();
}
public ServerWithSecurityGroups build() {
return new ServerWithSecurityGroups(this);
}
public T fromServerWithSecurityGroups(ServerWithSecurityGroups in) {
return super.fromServer(in).securityGroupNames(in.getSecurityGroupNames());
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
@SerializedName(value="security_groups")
private final Set<String> securityGroupNames;
protected ServerWithSecurityGroups(Builder<?> builder) {
super(builder);
this.securityGroupNames = ImmutableSet.copyOf(checkNotNull(builder.securityGroupNames, "securityGroupNames"));
}
/**
*/
public Set<String> getSecurityGroupNames() {
return Collections.unmodifiableSet(this.securityGroupNames);
}
@Override
public int hashCode() {
return Objects.hashCode(securityGroupNames);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
ServerWithSecurityGroups that = ServerWithSecurityGroups.class.cast(obj);
return super.equals(that) && Objects.equal(this.securityGroupNames, that.securityGroupNames);
}
protected ToStringHelper string() {
return super.string()
.add("securityGroupNames", securityGroupNames);
}
}

View File

@ -0,0 +1,129 @@
/**
* 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 com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.gson.annotations.SerializedName;
/**
* Represents a Virtual Interface (VIF)
*
* @author Adam Lowe
* @see org.jclouds.openstack.nova.v1_1.extensions.VirtualInterfaceClient
*/
public class VirtualInterface {
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromVirtualInterface(this);
}
public static abstract class Builder<T extends Builder<T>> {
protected abstract T self();
private String id;
private String macAddress;
/**
* @see VirtualInterface#getId()
*/
public T id(String id) {
this.id = id;
return self();
}
/**
* @see VirtualInterface#getMacAddress()
*/
public T macAddress(String macAddress) {
this.macAddress = macAddress;
return self();
}
public VirtualInterface build() {
return new VirtualInterface(this);
}
public T fromVirtualInterface(VirtualInterface in) {
return this
.id(in.getId())
.macAddress(in.getMacAddress())
;
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
private final String id;
@SerializedName(value="mac_address")
private final String macAddress;
protected VirtualInterface(Builder<?> builder) {
this.id = checkNotNull(builder.id, "id");
this.macAddress = checkNotNull(builder.macAddress, "macAddress");
}
public String getId() {
return this.id;
}
public String getMacAddress() {
return this.macAddress;
}
@Override
public int hashCode() {
return Objects.hashCode(id, macAddress);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
VirtualInterface that = VirtualInterface.class.cast(obj);
return Objects.equal(this.id, that.id)
&& Objects.equal(this.macAddress, that.macAddress)
;
}
protected ToStringHelper string() {
return Objects.toStringHelper("")
.add("id", id)
.add("macAddress", macAddress)
;
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -0,0 +1,167 @@
/**
* 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.concurrent.TimeUnit;
import javax.ws.rs.Consumes;
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.concurrent.Timeout;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
import org.jclouds.openstack.nova.v1_1.functions.ParseImageIdFromLocationHeader;
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provide access to Admin Server Actions via REST API
*
* @author Adam Lowe
* @see org.jclouds.openstack.nova.v1_1.extensions.AdminActionsClient
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
@SkipEncoding( { '/', '=' })
@RequestFilters(AuthenticateRequest.class)
@Path("/servers/{id}/action")
public interface AdminActionsAsyncClient {
/**
* @see AdminActionsClient#suspendServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"suspend\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> suspendServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#resumeServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"resume\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> resumeServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#migrateServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"migrate\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> migrateServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#suspendServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"lock\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> lockServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#unlockServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"unlock\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> unlockServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#resetNetworkOfServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"resetNetwork\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> resetNetworkOfServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#createBackupOfServer
*/
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"createBackup\":%7B\"name\":\"{name}\",\"backup_type\":\"{backup_type}\",\"rotation\":{rotation}%7D%7D")
@ExceptionParser(MapHttp4xxCodesToExceptions.class)
@ResponseParser(ParseImageIdFromLocationHeader.class)
ListenableFuture<String> createBackupOfServer(@PathParam("id") String id,
@PayloadParam("name") String imageName,
@PayloadParam("backup_type") BackupType backupType,
@PayloadParam("rotation") int rotation,
CreateBackupOfServerOptions... options);
/**
* @see AdminActionsClient#pauseServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"pause\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> pauseServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#unpauseServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"unpause\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> unpauseServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#suspendServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"injectNetworkInfo\":null}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
ListenableFuture<Boolean> injectNetworkInfoIntoServer(@PathParam("id") String id);
/**
* @see AdminActionsClient#migrateServer(String)
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
@Payload("%7B\"os-migrateLive\":%7B\"host\":\"{host}\",\"block_migration\":\"{bm}\",\"disk_over_commit\":\"{doc}\"%7D%7D")
ListenableFuture<Boolean> liveMigrateServer(@PathParam("id") String id,
@PayloadParam("host") String host,
@PayloadParam("bm") boolean blockMigration,
@PayloadParam("doc") boolean diskOverCommit);
}

View File

@ -0,0 +1,123 @@
/**
* 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.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
/**
* Provide additional actions for servers:
* 'suspend', 'resume', 'migrate', 'lock', 'unlock', 'resetNetwork', 'createBackup', 'pause', 'migrateLive',
* 'injectNetworkInfo', 'unpause'
*
* @author Adam Lowe
* @see org.jclouds.openstack.nova.v1_1.extensions.AdminActionsAsyncClient
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
public interface AdminActionsClient {
/**
* Suspend a server.
*
* @param id id of the server
*/
Boolean suspendServer(String id);
/**
* Resume a server.
*
* @param id id of the server
*/
Boolean resumeServer(String id);
/**
* Migrate a server.
*
* @param id id of the server
*/
Boolean migrateServer(String id);
/**
* Lock a server.
*
* @param id id of the server
*/
Boolean lockServer(String id);
/**
* Unlock a server.
*
* @param id id of the server
*/
Boolean unlockServer(String id);
/**
* Reset network of a server.
*
* @param id id of the server
*/
Boolean resetNetworkOfServer(String id);
/**
* Create backup of a server.
*
* @param id id of the server
* @param imageName the name of the image to create
* @param backupType the type of backup
* @param rotation the number of images to retain (0 to simply overwrite)
* @param options optional rotation and/or metadata parameters
* @return the id of the newly created image
*/
String createBackupOfServer(String id, String imageName, BackupType backupType, int rotation, CreateBackupOfServerOptions... options);
/**
* Pause a server.
*
* @param id id of the server
*/
Boolean pauseServer(String id);
/**
* Unpause a server.
*
* @param id id of the server
*/
Boolean unpauseServer(String id);
/**
* Live migrate a server.
*
* @param id id of the server
*/
Boolean liveMigrateServer(String id, String host, boolean blockMigration, boolean diskOverCommit);
/**
* Inject network info into a server.
*
* @param id id of the server
*/
Boolean injectNetworkInfoIntoServer(String id);
}

View File

@ -85,5 +85,8 @@ public interface ExtensionNamespaces {
* Instance rescue mode
*/
public static final String RESCUE = "http://docs.openstack.org/ext/rescue/api/v1.1";
/**
* Admin Action extension
*/
public static final String ADMIN_ACTIONS = "http://docs.openstack.org/ext/admin-actions/api/v1.1";
}

View File

@ -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.openstack.nova.v1_1.extensions;
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.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.ServerWithSecurityGroups;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides synchronous access to Servers with Security Groups.
*
* @author Adam Lowe
* @see org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient
* @see ServerWithSecurityGroupsClient
* @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.createserverext.html"/>
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.CREATESERVEREXT)
@SkipEncoding({'/', '='})
@RequestFilters(AuthenticateRequest.class)
public interface ServerWithSecurityGroupsAsyncClient {
/**
* @see ServerWithSecurityGroupsClient#getServer(String)
*/
@GET
@SelectJson("server")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/os-create-server-ext/{id}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<ServerWithSecurityGroups> getServer(@PathParam("id") String id);
}

View File

@ -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.openstack.nova.v1_1.extensions;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.v1_1.domain.ServerWithSecurityGroups;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
/**
* Provides synchronous access to Server details including security group, referred to as the CREATESERVEREXT extension
* in the nova documentation
* <p/>
* NOTE: the equivalent to listServersInDetail() isn't available at the other end, so not extending ServerClient at this
* time.
*
* @author Adam Lowe
* @see org.jclouds.openstack.nova.v1_1.features.ServerClient
* @see ServerWithSecurityGroupsAsyncClient
* @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.createserverext.html"/>
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.CREATESERVEREXT)
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
public interface ServerWithSecurityGroupsClient {
/**
* Retrieve details of the specified server, including security groups
*
* @param id id of the server
* @return server or null if not found
*/
ServerWithSecurityGroups getServer(String id);
}

View File

@ -0,0 +1,60 @@
/**
* 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.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.VirtualInterface;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
import org.jclouds.rest.annotations.ExceptionParser;
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 com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Virtual Interface features (VIFs).
*
* @see VirtualInterfaceClient
* @author Adam Lowe
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VIRTUAL_INTERFACES)
@SkipEncoding({'/', '='})
@RequestFilters(AuthenticateRequest.class)
public interface VirtualInterfaceAsyncClient {
/**
* @see VirtualInterfaceClient#listVirtualInterfacesForServer(String)
*/
@GET
@SelectJson("virtual_interfaces")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/servers/{server_id}/os-virtual-interfaces")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<VirtualInterface>> listVirtualInterfacesForServer(@PathParam("server_id") String serverId);
}

View File

@ -0,0 +1,46 @@
/**
* 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.VirtualInterface;
import org.jclouds.openstack.services.Extension;
import org.jclouds.openstack.services.ServiceType;
/**
* Provides synchronous access to Virtual Interface features (VIFs).
*
* @see VirtualInterfaceAsyncClient
* @author Adam Lowe
*/
@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VIRTUAL_INTERFACES)
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
public interface VirtualInterfaceClient {
/**
* Returns the list of Virtual Interfaces for a given instance.
*
* @return the list of snapshots
*/
Set<VirtualInterface> listVirtualInterfacesForServer(String serverId);
}

View File

@ -68,6 +68,12 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
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"))
.put(URI.create(ExtensionNamespaces.VIRTUAL_INTERFACES),
URI.create("http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1"))
.put(URI.create(ExtensionNamespaces.CREATESERVEREXT),
URI.create("http://docs.openstack.org/compute/ext/createserverext/api/v1.1"))
.put(URI.create(ExtensionNamespaces.ADMIN_ACTIONS),
URI.create("http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"))
.build();
@Inject

View File

@ -0,0 +1,107 @@
/**
* 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 CreateBackupOfServerOptions implements MapBinder {
public static final CreateBackupOfServerOptions NONE = new CreateBackupOfServerOptions();
@Inject
protected BindToJsonPayload jsonBinder;
private Map<String, String> metadata = ImmutableMap.of();
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
Map<String, Object> data = Maps.newHashMap();
data.putAll(postParams);
data.put("metadata", metadata);
return jsonBinder.bindToRequest(request, ImmutableMap.of("createBackup", data));
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
throw new IllegalStateException("createBackupOfServer is a POST operation");
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof CreateBackupOfServerOptions)) return false;
final CreateBackupOfServerOptions other = CreateBackupOfServerOptions.class.cast(object);
return equal(metadata, other.metadata);
}
@Override
public int hashCode() {
return Objects.hashCode(metadata);
}
protected ToStringHelper string() {
return toStringHelper("").add("metadata", metadata);
}
@Override
public String toString() {
return string().toString();
}
/** @see #getMetadata() */
public CreateBackupOfServerOptions metadata(Map<String, String> metadata) {
this.metadata = metadata;
return this;
}
/**
* Extra image properties to include
*/
public Map<String, String> getMetadata() {
return metadata;
}
public static class Builder {
/**
* @see CreateBackupOfServerOptions#getMetadata()
*/
public static CreateBackupOfServerOptions metadata(Map<String, String> metadata) {
return new CreateBackupOfServerOptions().metadata(metadata);
}
}
}

View File

@ -1,10 +1,13 @@
package org.jclouds.openstack.nova.v1_1.compute;
import static java.util.logging.Logger.getAnonymousLogger;
import java.util.Properties;
import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.nova.v1_1.config.NovaProperties;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
@ -31,9 +34,16 @@ public class NovaComputeServiceLiveTest extends BaseComputeServiceLiveTest {
// start call is blocking anyway.
}
@Test(enabled = true, dependsOnMethods = "testReboot", expectedExceptions = UnsupportedOperationException.class)
@Test(enabled = true, dependsOnMethods = "testReboot")
public void testSuspendResume() throws Exception {
super.testSuspendResume();
try {
// may fail because of lack of AdminActions extension or non-admin user, so log and continue
super.testSuspendResume();
} catch (AuthorizationException e) {
getAnonymousLogger().info("testSuspendResume() threw, probably due to lack of privileges: " + e.getMessage());
} catch (UnsupportedOperationException e) {
getAnonymousLogger().info("testSuspendResume() threw, probably due to unavailable AdminActions extension: " + e.getMessage());
}
}
@Test(enabled = true, dependsOnMethods = "testSuspendResume")

View File

@ -0,0 +1,352 @@
/**
* 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.assertFalse;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpRequest;
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
/**
* Tests parsing and guice wiring of AdminActionsClient
*
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "AdminActionsClientExpectTest")
public class AdminActionsClientExpectTest extends BaseNovaClientExpectTest {
public void testSuspend() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.suspendServer("1"));
}
public void testSuspendFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.suspendServer("1"));
}
@Test(expectedExceptions = AuthorizationException.class)
public void testSuspendFailsNotAuthorized() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
standardResponseBuilder(403).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
client.suspendServer("1");
}
public void testResume() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.resumeServer("1"));
}
public void testResumeFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.resumeServer("1"));
}
@Test(expectedExceptions = AuthorizationException.class)
public void testResumeFailsNotAuthorized() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
standardResponseBuilder(403).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
client.resumeServer("1");
}
public void testLock() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "lock").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.lockServer("1"));
}
public void testLockFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "lock").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.lockServer("1"));
}
public void testUnlock() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "unlock").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.unlockServer("1"));
}
public void testUnlockFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "unlock").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.unlockServer("1"));
}
public void testPause() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "pause").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.pauseServer("1"));
}
public void testPauseFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "pause").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.pauseServer("1"));
}
public void testUnpause() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "unpause").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.unpauseServer("1"));
}
public void testUnpauseFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "unpause").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.unpauseServer("1"));
}
public void testMigrateServer() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "migrate").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.migrateServer("1"));
}
public void testMigrateServerFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "migrate").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.migrateServer("1"));
}
public void testResetNetworkOfServer() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "resetNetwork").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.resetNetworkOfServer("1"));
}
public void testResetNetworkOfServerFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "resetNetwork").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.resetNetworkOfServer("1"));
}
public void testInjectNetworkInfoIntoServer() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "injectNetworkInfo").build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.injectNetworkInfoIntoServer("1"));
}
public void testInjectNetworkInfoIntoServerFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "injectNetworkInfo").build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.injectNetworkInfoIntoServer("1"));
}
public void testBackupServer() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("POST")
.payload(payloadFromStringWithContentType("{\"createBackup\":{\"backup_type\":\"weekly\",\"rotation\":\"3\",\"name\":\"mybackup\",\"metadata\":{\"some\":\"data or other\"}}}", MediaType.APPLICATION_JSON)).build(),
standardResponseBuilder(202).headers(ImmutableMultimap.of("Location", "http://172.16.89.149:8774/v2/images/1976b3b3-409a-468d-b16c-a9172c341b46")).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
String imageId = client.createBackupOfServer("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
assertEquals(imageId, "1976b3b3-409a-468d-b16c-a9172c341b46");
}
@Test(expectedExceptions = ResourceNotFoundException.class)
public void testBackupServerFailNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).method("POST")
.payload(payloadFromStringWithContentType("{\"createBackup\":{\"backup_type\":\"weekly\",\"rotation\":\"3\",\"name\":\"mybackup\",\"metadata\":{\"some\":\"data or other\"}}}", MediaType.APPLICATION_JSON)).build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
client.createBackupOfServer("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
}
public void testLiveMigrateServer() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "GONNAOVERWRITE")
.payload(payloadFromStringWithContentType("{\"os-migrateLive\":{\"host\":\"bighost\",\"block_migration\":\"true\",\"disk_over_commit\":\"false\"}}", MediaType.APPLICATION_JSON)).build(),
standardResponseBuilder(202).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.liveMigrateServer("1", "bighost", true, false));
}
public void testLiveMigrateServerFailsNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/action");
AdminActionsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardActionRequestBuilderVoidResponse(endpoint, "GONNAOVERWRITE")
.payload(payloadFromStringWithContentType("{\"os-migrateLive\":{\"host\":\"bighost\",\"block_migration\":\"true\",\"disk_over_commit\":\"false\"}}", MediaType.APPLICATION_JSON)).build(),
standardResponseBuilder(404).build()
).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
assertFalse(client.liveMigrateServer("1", "bighost", true, false));
}
protected HttpRequest.Builder standardActionRequestBuilderVoidResponse(URI endpoint, String actionName) {
return HttpRequest.builder().method("POST")
.headers(ImmutableMultimap.of("X-Auth-Token", authToken))
.payload(payloadFromStringWithContentType("{\"" + actionName + "\":null}", MediaType.APPLICATION_JSON))
.endpoint(endpoint);
}
}

View File

@ -0,0 +1,191 @@
/**
* 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 static org.testng.Assert.fail;
import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.features.ExtensionClient;
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.internal.BaseNovaClientLiveTest;
import org.jclouds.openstack.nova.v1_1.options.CreateBackupOfServerOptions;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/**
* Tests behavior of HostAdministrationClient
*
* TODO test migration methods
*
* @author Adam Lowe
*/
@Test(groups = "live", testName = "AdminActionsClientLiveTest", singleThreaded = true)
public class AdminActionsClientLiveTest extends BaseNovaClientLiveTest {
private ImageClient imageClient;
private ServerClient serverClient;
private ExtensionClient extensionClient;
private Optional<AdminActionsClient> clientOption;
private String zone;
private String testServerId;
private String backupImageId;
@BeforeGroups(groups = {"integration", "live"})
@Override
public void setupContext() {
super.setupContext();
zone = Iterables.getLast(novaContext.getApi().getConfiguredZones(), "nova");
serverClient = novaContext.getApi().getServerClientForZone(zone);
extensionClient = novaContext.getApi().getExtensionClientForZone(zone);
imageClient = novaContext.getApi().getImageClientForZone(zone);
clientOption = novaContext.getApi().getAdminActionsExtensionForZone(zone);
if (clientOption.isPresent()) {
testServerId = createServerInZone(zone).getId();
}
}
@AfterGroups(groups = "live", alwaysRun = true)
@Override
protected void tearDown() {
if (clientOption.isPresent()) {
if (testServerId != null) {
assertTrue(novaContext.getApi().getServerClientForZone(zone).deleteServer(testServerId));
}
if (backupImageId != null) {
imageClient.deleteImage(backupImageId);
}
}
super.tearDown();
}
@AfterMethod(alwaysRun = true)
public void ensureServerIsActiveAgain() {
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
}
public void testSuspendAndResume() {
if (clientOption.isPresent()) {
AdminActionsClient client = clientOption.get();
// Suspend-resume
try {
client.resumeServer(testServerId);
fail("Resumed an active server!");
} catch (HttpResponseException e) {
}
assertTrue(client.suspendServer(testServerId));
blockUntilServerInState(testServerId, serverClient, Server.Status.SUSPENDED);
try {
client.suspendServer(testServerId);
fail("Suspended an already suspended server!");
} catch (HttpResponseException e) {
}
assertTrue(client.resumeServer(testServerId));
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
try {
client.resumeServer(testServerId);
fail("Resumed an already resumed server!");
} catch (HttpResponseException e) {
}
}
}
public void testLockAndUnlock() {
if (clientOption.isPresent()) {
AdminActionsClient client = clientOption.get();
// TODO should we be able to double-lock (as it were)
assertTrue(client.unlockServer(testServerId));
assertTrue(client.unlockServer(testServerId));
assertTrue(client.lockServer(testServerId));
assertTrue(client.lockServer(testServerId));
assertTrue(client.unlockServer(testServerId));
assertTrue(client.unlockServer(testServerId));
}
}
public void testResetNetworkAndInjectNetworkInfo() {
if (clientOption.isPresent()) {
AdminActionsClient client = clientOption.get();
assertTrue(client.resetNetworkOfServer(testServerId));
assertTrue(client.injectNetworkInfoIntoServer(testServerId));
}
}
@Test
public void testPauseAndUnpause() {
if (clientOption.isPresent()) {
AdminActionsClient client = clientOption.get();
// Unlock and lock (double-checking error contitions too)
try {
client.unpauseServer(testServerId);
fail("Unpaused active server!");
} catch (HttpResponseException e) {
}
assertTrue(client.pauseServer(testServerId));
blockUntilServerInState(testServerId, serverClient, Server.Status.PAUSED);
try {
client.pauseServer(testServerId);
fail("paused a paused server!");
} catch (HttpResponseException e) {
}
assertTrue(client.unpauseServer(testServerId));
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
try {
client.unpauseServer(testServerId);
fail("Unpaused a server we just unpaused!");
} catch (HttpResponseException e) {
}
}
}
@Test
public void testCreateBackupOfServer() throws InterruptedException {
if (clientOption.isPresent()) {
backupImageId = clientOption.get().createBackupOfServer(testServerId, "jclouds-test-backup", BackupType.DAILY, 0,
CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("test", "metadata")));
assertNotNull(backupImageId);
// If we don't have extended task status, we'll have to wait here!
if (extensionClient.getExtensionByAlias("OS-EXT-STS") == null) {
Thread.sleep(30000);
}
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
Image backupImage = imageClient.getImage(backupImageId);
assertEquals(backupImage.getId(), backupImageId);
}
}
}

View File

@ -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.openstack.nova.v1_1.extensions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import java.net.URI;
import org.jclouds.openstack.nova.v1_1.domain.ServerWithSecurityGroups;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests parsing and guice wiring of ServerWithSecurityGroupsClient
*
* @author Adam Lowe
*/
@Test(groups = "unit", testName = "ServerWithSecurityGroupsClientExpectTest")
public class ServerWithSecurityGroupsClientExpectTest extends BaseNovaClientExpectTest {
public void testGetServerWithSecurityGroups() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-create-server-ext/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
ServerWithSecurityGroupsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(200).payload(payloadFromResource("/server_with_security_groups.json")).build()
).getServerWithSecurityGroupsExtensionForZone("az-1.region-a.geo-1").get();
ServerWithSecurityGroups server = client.getServer("8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
assertEquals(server.getId(), "8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
assertEquals(server.getSecurityGroupNames(), ImmutableSet.of("default", "group1"));
}
public void testGetServerWithSecurityGroupsFailNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/os-create-server-ext/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
ServerWithSecurityGroupsClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(404).build()
).getServerWithSecurityGroupsExtensionForZone("az-1.region-a.geo-1").get();
assertNull(client.getServer("8d0a6ca5-8849-4b3d-b86e-f24c92490ebb"));
}
}

View File

@ -0,0 +1,82 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.extensions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.ServerWithSecurityGroups;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Tests behavior of ServerWithSecurityGroupsClient
*
* @author Adam Lowe
*/
@Test(groups = "live", testName = "ServerWithSecurityGroupsClientLiveTest", singleThreaded = true)
public class ServerWithSecurityGroupsClientLiveTest extends BaseNovaClientLiveTest {
private ServerClient serverClient;
private Optional<ServerWithSecurityGroupsClient> clientOption;
private String zone;
@BeforeGroups(groups = {"integration", "live"})
@Override
public void setupContext() {
super.setupContext();
zone = Iterables.getLast(novaContext.getApi().getConfiguredZones(), "nova");
serverClient = novaContext.getApi().getServerClientForZone(zone);
clientOption = novaContext.getApi().getServerWithSecurityGroupsExtensionForZone(zone);
}
public void testGetServer() {
if (clientOption.isPresent()) {
for (Resource server : serverClient.listServers()) {
ServerWithSecurityGroups serverWithGroups = clientOption.get().getServer(server.getId());
assertEquals(serverWithGroups.getId(), server.getId());
assertEquals(serverWithGroups.getName(), server.getName());
assertNotNull(serverWithGroups.getSecurityGroupNames());
}
// Create a new server to verify the groups work as expected
Server testServer = null;
try {
testServer = createServerInZone(zone);
ServerWithSecurityGroups results = clientOption.get().getServer(testServer.getId());
assertEquals(results.getId(), testServer.getId());
assertEquals(results.getSecurityGroupNames(), ImmutableSet.of("default"));
} finally {
if (testServer != null) {
serverClient.deleteServer(testServer.getId());
}
}
}
}
}

View File

@ -0,0 +1,65 @@
/**
* 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.assertTrue;
import java.net.URI;
import org.jclouds.openstack.nova.v1_1.domain.VirtualInterface;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.Iterables;
/**
* Tests parsing and guice wiring of VirtualInterfaceClient
*
* @author Adam Lowe
*/
@Test(groups = "live", testName = "VirtualInterfaceClientLiveTest")
public class VirtualInterfaceClientExpectTest extends BaseNovaClientExpectTest {
public void testListVirtualInterfaces() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/os-virtual-interfaces");
VirtualInterfaceClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(200).payload(payloadFromResource("/virtual_interfaces_list.json")).build()
).getVirtualInterfaceExtensionForZone("az-1.region-a.geo-1").get();
VirtualInterface vif = Iterables.getOnlyElement(client.listVirtualInterfacesForServer("1"));
assertEquals(vif.getId(), "02315827-b05c-4668-9c05-75c68838074a");
assertEquals(vif.getMacAddress(), "fa:16:3e:09:71:34");
}
public void testListVirtualInterfacesFailNotFound() {
URI endpoint = URI.create("https://compute.north.host/v1.1/3456/servers/1/os-virtual-interfaces");
VirtualInterfaceClient client = requestsSendResponses(
keystoneAuthWithUsernameAndPassword,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
standardRequestBuilder(endpoint).build(),
standardResponseBuilder(404).build()
).getVirtualInterfaceExtensionForZone("az-1.region-a.geo-1").get();
assertTrue(client.listVirtualInterfacesForServer("1").isEmpty());
}
}

View File

@ -0,0 +1,70 @@
/**
* 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.assertNotNull;
import java.util.Set;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.VirtualInterface;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
/**
* Tests behavior of VirtualInterfaceClient
*
* @author Adam Lowe
*/
@Test(groups = "live", testName = "VirtualInterfaceClientLiveTest", singleThreaded = true)
public class VirtualInterfaceClientLiveTest extends BaseNovaClientLiveTest {
private Optional<VirtualInterfaceClient> clientOption;
private String zone;
@BeforeClass(groups = {"integration", "live"})
@Override
public void setupContext() {
super.setupContext();
zone = Iterables.getLast(novaContext.getApi().getConfiguredZones(), "nova");
clientOption = novaContext.getApi().getVirtualInterfaceExtensionForZone(zone);
}
public void testListVirtualInterfaces() {
if (clientOption.isPresent()) {
Server testServer = null;
try {
testServer = createServerInZone(zone);
Set<VirtualInterface> results = clientOption.get().listVirtualInterfacesForServer(testServer.getId());
for (VirtualInterface vif : results) {
assertNotNull(vif.getId());
assertNotNull(vif.getMacAddress());
}
} finally {
if (testServer != null) {
novaContext.getApi().getServerClientForZone(zone).deleteServer(testServer.getId());
}
}
}
}
}

View File

@ -18,13 +18,18 @@
*/
package org.jclouds.openstack.nova.v1_1.internal;
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
import static org.jclouds.compute.util.ComputeServiceUtils.getSpace;
import java.util.Properties;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.config.NovaProperties;
import org.jclouds.openstack.nova.v1_1.domain.Flavor;
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;
@ -36,7 +41,9 @@ import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
/**
* Tests behavior of {@code NovaClient}
@ -76,15 +83,19 @@ public class BaseNovaClientLiveTest extends BaseComputeServiceContextLiveTest {
protected Server createServerInZone(String zoneId) {
ServerClient serverClient = novaContext.getApi().getServerClientForZone(zoneId);
Server server = serverClient.createServer("test", imageIdForZone(zoneId), flavorRefForZone(zoneId));
blockUntilServerActive(server.getId(), serverClient);
blockUntilServerInState(server.getId(), serverClient, Status.ACTIVE);
return server;
}
private void blockUntilServerActive(String serverId, ServerClient client) {
/**
* Will block until the requested server is in the correct state, if Extended Server Status extension is loaded
* this will continue to block while any task is in progress.
*/
protected void blockUntilServerInState(String serverId, ServerClient client, Status status) {
Server currentDetails = null;
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != Status.ACTIVE; currentDetails = client
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != status || currentDetails.getTaskState() != null; currentDetails = client
.getServer(serverId)) {
System.out.printf("blocking on status active%n%s%n", currentDetails);
System.out.printf("blocking on status %s%n%s%n", status, currentDetails);
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
@ -100,7 +111,13 @@ public class BaseNovaClientLiveTest extends BaseComputeServiceContextLiveTest {
protected String flavorRefForZone(String zoneId) {
FlavorClient flavorClient = novaContext.getApi().getFlavorClientForZone(zoneId);
return Iterables.getLast(flavorClient.listFlavors()).getId();
return DEFAULT_FLAVOR_ORDERING.min(flavorClient.listFlavorsInDetail()).getId();
}
static final Ordering<Flavor> DEFAULT_FLAVOR_ORDERING = new Ordering<Flavor>() {
public int compare(Flavor left, Flavor right) {
return ComparisonChain.start().compare(left.getVcpus(), right.getVcpus()).compare(left.getRam(), right.getRam())
.compare(left.getDisk(), right.getDisk()).result();
}
};
}

View File

@ -1,123 +1,281 @@
{"extensions": [
{
"extensions": [{
"updated": "2011-06-09T00:00:00+00:00",
"name": "Multinic",
"links": [],
"namespace": "https://docs.openstack.org/ext/multinic/api/v1.1",
"alias": "NMN",
"description": "Multiple network support"
}, {
"updated": "2011-06-29T00:00:00+00:00",
"name": "Hosts",
"links": [],
"namespace": "https://docs.openstack.org/ext/hosts/api/v1.1",
"alias": "os-hosts",
"description": "Host administration"
}, {
"updated": "2011-03-25T00:00:00+00:00",
"name": "Volumes",
"links": [],
"namespace": "https://docs.openstack.org/ext/volumes/api/v1.1",
"alias": "os-volumes",
"description": "Volumes support"
}, {
"updated": "2011-05-25 16:12:21.656723",
"name": "Admin Controller",
"links": [],
"namespace": "https:TODO/",
"alias": "ADMIN",
"description": "The Admin API Extension"
}, {
"updated": "2011-08-08T00:00:00+00:00",
"name": "Quotas",
"links": [],
"namespace": "https://docs.openstack.org/ext/quotas-sets/api/v1.1",
"alias": "os-quota-sets",
"description": "Quotas management support"
}, {
"updated": "2011-08-24T00:00:00+00:00",
"name": "VolumeTypes",
"links": [],
"namespace": "https://docs.openstack.org/ext/volume_types/api/v1.1",
"alias": "os-volume-types",
"description": "Volume types support"
}, {
"updated": "2011-06-23T00:00:00+00:00",
"name": "FlavorExtraSpecs",
"links": [],
"namespace": "https://docs.openstack.org/ext/flavor_extra_specs/api/v1.1",
"alias": "os-flavor-extra-specs",
"description": "Instance type (flavor) extra specs"
}, {
"updated": "2011-09-14T00:00:00+00:00",
"name": "FlavorExtraData",
"links": [],
"namespace": "https://docs.openstack.org/ext/flavor_extra_data/api/v1.1",
"alias": "os-flavor-extra-data",
"description": "Provide additional data for flavors"
}, {
"updated": "2011-08-17T00:00:00+00:00",
"name": "VirtualInterfaces",
"links": [],
"namespace": "https://docs.openstack.org/ext/virtual_interfaces/api/v1.1",
"alias": "virtual_interfaces",
"description": "Virtual interface support"
}, {
"updated": "2011-07-19T00:00:00+00:00",
"name": "Createserverext",
"links": [],
"namespace": "https://docs.openstack.org/ext/createserverext/api/v1.1",
"alias": "os-create-server-ext",
"description": "Extended support to the Create Server v1.1 API"
}, {
"updated": "2011-08-08T00:00:00+00:00",
"name": "Keypairs",
"links": [],
"namespace": "https://docs.openstack.org/ext/keypairs/api/v1.1",
"alias": "os-keypairs",
"description": "Keypair Support"
}, {
"updated": "2011-08-25T00:00:00+00:00",
"name": "VSAs",
"links": [],
"namespace": "https://docs.openstack.org/ext/vsa/api/v1.1",
"alias": "zadr-vsa",
"description": "Virtual Storage Arrays support"
}, {
"updated": "2011-08-19T00:00:00+00:00",
"name": "SimpleTenantUsage",
"links": [],
"namespace": "https://docs.openstack.org/ext/os-simple-tenant-usage/api/v1.1",
"alias": "os-simple-tenant-usage",
"description": "Simple tenant usage extension"
}, {
"updated": "2011-08-18T00:00:00+00:00",
"name": "Rescue",
"links": [],
"namespace": "https://docs.openstack.org/ext/rescue/api/v1.1",
"alias": "os-rescue",
"description": "Instance rescue mode"
}, {
"updated": "2011-07-21T00:00:00+00:00",
"name": "SecurityGroups",
"links": [],
"namespace": "https://docs.openstack.org/ext/securitygroups/api/v1.1",
"alias": "security_groups",
"description": "Security group support"
}, {
"updated": "2011-06-16T00:00:00+00:00",
"name": "Floating_ips",
"links": [],
"namespace": "https://docs.openstack.org/ext/floating_ips/api/v1.1",
"alias": "os-floating-ips",
"description": "Floating IPs support"
}, {
"updated": "2011-06-16T00:00:00+00:00",
"name": "Users",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/users/api/v1.1",
"alias": "os-users",
"description": "Users support"
}
]
}
"updated": "2011-09-27T00:00:00+00:00",
"name": "DiskConfig",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/disk_config/api/v1.1",
"alias": "OS-DCF",
"description": "Disk Management Extension"
},
{
"updated": "2011-06-29T00:00:00+00:00",
"name": "Hosts",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/hosts/api/v1.1",
"alias": "os-hosts",
"description": "Admin-only host administration"
},
{
"updated": "2011-07-19T00:00:00+00:00",
"name": "SchedulerHints",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/scheduler-hints/api/v2",
"alias": "os-scheduler-hints",
"description": "Pass arbitrary key/value pairs to the scheduler"
},
{
"updated": "2011-08-08T00:00:00+00:00",
"name": "Quotas",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1",
"alias": "os-quota-sets",
"description": "Quotas management support"
},
{
"updated": "2011-12-23T00:00:00+00:00",
"name": "Floating_ip_dns",
"links": [],
"namespace": "http://docs.openstack.org/ext/floating_ip_dns/api/v1.1",
"alias": "os-floating-ip-dns",
"description": "Floating IP DNS support"
},
{
"updated": "2011-09-14T00:00:00+00:00",
"name": "FlavorExtraData",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1",
"alias": "OS-FLV-EXT-DATA",
"description": "Provide additional data for flavors"
},
{
"updated": "2011-06-23T00:00:00+00:00",
"name": "FlavorExtraSpecs",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/flavor_extra_specs/api/v1.1",
"alias": "os-flavor-extra-specs",
"description": "Instance type (flavor) extra specs"
},
{
"updated": "2011-08-17T00:00:00+00:00",
"name": "VirtualInterfaces",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1",
"alias": "virtual_interfaces",
"description": "Virtual interface support"
},
{
"updated": "2011-12-23T00:00:00+00:00",
"name": "Accounts",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/accounts/api/v1.1",
"alias": "os-accounts",
"description": "Admin-only access to accounts"
},
{
"updated": "2011-03-25T00:00:00+00:00",
"name": "Volumes",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/volumes/api/v1.1",
"alias": "os-volumes",
"description": "Volumes support"
},
{
"updated": "2011-11-03T00:00:00+00:00",
"name": "ExtendedStatus",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/extended_status/api/v1.1",
"alias": "OS-EXT-STS",
"description": "Extended Status support"
},
{
"updated": "2011-12-23T00:00:00+00:00",
"name": "Consoles",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/os-consoles/api/v2",
"alias": "os-consoles",
"description": "Interactive Console support."
},
{
"updated": "2011-07-21T00:00:00+00:00",
"name": "SecurityGroups",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/securitygroups/api/v1.1",
"alias": "security_groups",
"description": "Security group support"
},
{
"updated": "2012-01-12T00:00:00+00:00",
"name": "Aggregates",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/aggregates/api/v1.1",
"alias": "os-aggregates",
"description": "Admin-only aggregate administration"
},
{
"updated": "2011-07-19T00:00:00+00:00",
"name": "Createserverext",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/createserverext/api/v1.1",
"alias": "os-create-server-ext",
"description": "Extended support to the Create Server v1.1 API"
},
{
"updated": "2011-09-01T00:00:00+00:00",
"name": "DeferredDelete",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/deferred-delete/api/v1.1",
"alias": "os-deferred-delete",
"description": "Instance deferred delete"
},
{
"updated": "2011-12-21T00:00:00+00:00",
"name": "ServerDiagnostics",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/server-diagnostics/api/v1.1",
"alias": "os-server-diagnostics",
"description": "Allow Admins to view server diagnostics through server action"
},
{
"updated": "2011-12-23T00:00:00+00:00",
"name": "Networks",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/networks/api/v1.1",
"alias": "os-networks",
"description": "Admin-only Network Management Extension"
},
{
"updated": "2011-11-03T00:00:00+00:00",
"name": "ExtendedServerAttributes",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/extended_status/api/v1.1",
"alias": "OS-EXT-SRV-ATTR",
"description": "Extended Server Attributes support."
},
{
"updated": "2011-08-08T00:00:00+00:00",
"name": "Keypairs",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/keypairs/api/v1.1",
"alias": "os-keypairs",
"description": "Keypair Support"
},
{
"updated": "2011-08-24T00:00:00+00:00",
"name": "VolumeTypes",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/volume_types/api/v1.1",
"alias": "os-volume-types",
"description": "Volume types support"
},
{
"updated": "2011-08-19T00:00:00+00:00",
"name": "SimpleTenantUsage",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1",
"alias": "os-simple-tenant-usage",
"description": "Simple tenant usage extension"
},
{
"updated": "2012-01-04T00:00:00+00:00",
"name": "Floating_ip_pools",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/floating_ip_pools/api/v1.1",
"alias": "os-floating-ip-pools",
"description": "Floating IPs support"
},
{
"updated": "2012-01-23T00:00:00+00:00",
"name": "ServerStartStop",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/servers/api/v1.1",
"alias": "os-server-start-stop",
"description": "Start/Stop instance compute API support"
},
{
"updated": "2012-03-12T00:00:00+00:00",
"name": "QuotaClasses",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1",
"alias": "os-quota-class-sets",
"description": "Quota classes management support"
},
{
"updated": "2012-01-19T00:00:00+00:00",
"name": "Certificates",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/certificates/api/v1.1",
"alias": "os-certificates",
"description": "Certificates support"
},
{
"updated": "2011-08-18T00:00:00+00:00",
"name": "Rescue",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
"alias": "os-rescue",
"description": "Instance rescue mode"
},
{
"updated": "2012-01-19T00:00:00+00:00",
"name": "FlavorManage",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/flavor_manage/api/v1.1",
"alias": "os-flavor-manage",
"description": "\n Flavor create/delete API support\n "
},
{
"updated": "2011-12-16T00:00:00+00:00",
"name": "Cloudpipe",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/cloudpipe/api/v1.1",
"alias": "os-cloudpipe",
"description": "Adds actions to create cloudpipe instances.\n\n When running with the Vlan network mode, you need a mechanism to route\n from the public Internet to your vlans. This mechanism is known as a\n cloudpipe.\n\n At the time of creating this class, only OpenVPN is supported. Support for\n a SSH Bastion host is forthcoming.\n "
},
{
"updated": "2011-06-09T00:00:00+00:00",
"name": "Multinic",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/multinic/api/v1.1",
"alias": "NMN",
"description": "Multiple network support"
},
{
"updated": "2011-08-08T00:00:00+00:00",
"name": "Users",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/users/api/v1.1",
"alias": "os-users",
"description": "Allow admins to acces user information"
},
{
"updated": "2011-09-20T00:00:00+00:00",
"name": "AdminActions",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/admin-actions/api/v1.1",
"alias": "os-admin-actions",
"description": "Enable admin-only server actions\n\n Actions include: pause,unpause, suspend, resume, migrate,\n resetNetwork, injectNetworkInfo, lock, unlock, createBackup\n "
},
{
"updated": "2011-12-21T00:00:00+00:00",
"name": "ServerActionList",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/server-actions-list/api/v1.1",
"alias": "os-server-action-list",
"description": "Allow Admins to view pending server actions"
},
{
"updated": "2011-12-08T00:00:00+00:00",
"name": "Console_output",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/os-console-output/api/v2",
"alias": "os-console-output",
"description": "Console log output support, with tailing ability."
},
{
"updated": "2011-06-16T00:00:00+00:00",
"name": "Floating_ips",
"links": [],
"namespace": "http://docs.openstack.org/compute/ext/floating_ips/api/v1.1",
"alias": "os-floating-ips",
"description": "Floating IPs support"}
]}

View File

@ -0,0 +1 @@
{"server": {"status": "ACTIVE", "updated": "2012-05-04T12:15:01Z", "hostId": "02c7c81e36024d2bfdb473cb762900138bc07777922479d3d4f8f690", "user_id": "1e8a56719e0d4ab4b7edb85c77f7290f", "name": "test", "links": [{"href": "http://172.16.89.148:8774/v2/4287930c796741aa898425f40832cb3c/servers/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb", "rel": "self"}, {"href": "http://172.16.89.148:8774/4287930c796741aa898425f40832cb3c/servers/8d0a6ca5-8849-4b3d-b86e-f24c92490ebb", "rel": "bookmark"}], "created": "2012-05-04T12:14:57Z", "tenant_id": "4287930c796741aa898425f40832cb3c", "image": {"id": "ea17cc36-f7c9-40cd-b6bf-a952b74870f2", "links": [{"href": "http://172.16.89.148:8774/4287930c796741aa898425f40832cb3c/images/ea17cc36-f7c9-40cd-b6bf-a952b74870f2", "rel": "bookmark"}]}, "addresses": {"private": [{"version": 4, "addr": "10.0.0.8"}]}, "accessIPv4": "", "accessIPv6": "", "key_name": "", "progress": 0, "flavor": {"id": "1", "links": [{"href": "http://172.16.89.148:8774/4287930c796741aa898425f40832cb3c/flavors/1", "rel": "bookmark"}]}, "config_drive": "", "id": "8d0a6ca5-8849-4b3d-b86e-f24c92490ebb", "security_groups": [{"name": "default"},{"name": "group1"}], "metadata": {}}}

View File

@ -0,0 +1 @@
{"virtual_interfaces": [{"id": "02315827-b05c-4668-9c05-75c68838074a", "mac_address": "fa:16:3e:09:71:34"}]}

View File

@ -19,10 +19,9 @@
package org.jclouds.openstack.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.Collections;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
@ -41,67 +40,80 @@ import com.google.common.collect.ImmutableSet;
*/
public class Resource implements Comparable<Resource> {
public static Builder builder() {
return new Builder();
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder toBuilder() {
return builder().fromResource(this);
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromResource(this);
}
public static class Builder {
protected String id;
protected String name;
protected Set<Link> links = ImmutableSet.of();
public static abstract class Builder<T extends Builder<T>> {
protected abstract T self();
private String id;
private String name;
private Set<Link> links = ImmutableSet.of();
/**
* @see Resource#getId()
*/
public Builder id(String id) {
this.id = checkNotNull(id, "id");
return this;
public T id(String id) {
this.id = id;
return self();
}
/**
* @see Resource#getName()
*/
public Builder name(@Nullable String name) {
public T name(String name) {
this.name = name;
return this;
return self();
}
/**
* @see Resource#getLinks()
*/
public Builder links(Link... links) {
public T links(Link... links) {
return links(ImmutableSet.copyOf(checkNotNull(links, "links")));
}
/**
* @see Resource#getLinks()
*/
public Builder links(Set<Link> links) {
this.links = ImmutableSet.copyOf(checkNotNull(links, "links"));
return this;
public T links(Set<Link> links) {
this.links = links;
return self();
}
public Resource build() {
return new Resource(id, name, links);
return new Resource(this);
}
public Builder fromResource(Resource from) {
return id(from.getId()).name(from.getName()).links(from.getLinks());
public T fromResource(Resource in) {
return this
.id(in.getId())
.name(in.getName())
.links(in.getLinks())
;
}
}
protected final String id;
protected final String name;
protected final Set<Link> links;
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
public Resource(String id,@Nullable String name, Set<Link> links) {
this.id = checkNotNull(id, "id");
this.name = name;
this.links = ImmutableSet.copyOf(checkNotNull(links, "links"));
private final String id;
private final String name;
private final Set<Link> links;
protected Resource(Builder<?> builder) {
this.id = checkNotNull(builder.id, "id");
this.name = builder.name;
this.links = ImmutableSet.copyOf(checkNotNull(builder.links, "links"));
}
/**
@ -126,36 +138,35 @@ public class Resource implements Comparable<Resource> {
* @return the links of the id address allocated to the new server
*/
public Set<Link> getLinks() {
return links;
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object instanceof Resource) {
final Resource other = Resource.class.cast(object);
return equal(getId(), other.getId()) && equal(name, other.name) && equal(links, other.links);
} else {
return false;
}
return Collections.unmodifiableSet(this.links);
}
@Override
public int hashCode() {
return Objects.hashCode(getId(), name, links);
return Objects.hashCode(id, name, links);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Resource that = Resource.class.cast(obj);
return Objects.equal(this.getId(), that.getId())
&& Objects.equal(this.name, that.name)
&& Objects.equal(this.links, that.links);
}
protected ToStringHelper string() {
return Objects.toStringHelper("")
.add("id", getId())
.add("name", name)
.add("links", links);
}
@Override
public String toString() {
return string().toString();
}
protected ToStringHelper string() {
return toStringHelper("").add("id", getId()).add("name", name).add("links", links);
}
@Override
public int compareTo(Resource that) {
if (that == null)

View File

@ -25,7 +25,6 @@ import java.util.Date;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import com.google.common.base.Objects;
@ -35,111 +34,96 @@ import com.google.common.collect.Sets;
import com.google.gson.annotations.SerializedName;
/**
* Class ApiMetadata
* @author Adam Lowe
*/
public class ApiMetadata extends Resource {
public static Builder builder() {
return new Builder();
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder toBuilder() {
return new Builder().fromApiMetadata(this);
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromApiMetadata(this);
}
public static class Builder extends Resource.Builder {
public static abstract class Builder<T extends Builder<T>> extends Resource.Builder<T> {
private String status;
private Date updated;
private Set<MediaType> mediaTypes = Sets.newLinkedHashSet();
public Builder status(String status) {
/**
* @see ApiMetadata#getStatus()
*/
public T status(String status) {
this.status = status;
return this;
return self();
}
public Builder updated(Date updated) {
/**
* @see ApiMetadata#getUpdated()
*/
public T updated(Date updated) {
this.updated = updated;
return this;
return self();
}
public Builder mediaTypes(Set<MediaType> mediaTypes) {
/**
* @see ApiMetadata#getMediaTypes()
*/
public T mediaTypes(Set<MediaType> mediaTypes) {
this.mediaTypes = mediaTypes;
return this;
return self();
}
public ApiMetadata build() {
return new ApiMetadata(id, name, links, updated, status, mediaTypes);
return new ApiMetadata(this);
}
public Builder fromApiMetadata(ApiMetadata in) {
return fromResource(in)
public T fromApiMetadata(ApiMetadata in) {
return super.fromResource(in)
.status(in.getStatus())
.updated(in.getUpdated())
.mediaTypes(in.getMediaTypes());
}
/**
* {@inheritDoc}
*/
@Override
public Builder id(String id) {
return Builder.class.cast(super.id(id));
}
}
/**
* {@inheritDoc}
*/
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
public Builder name(String name) {
return Builder.class.cast(super.name(name));
}
/**
* {@inheritDoc}
*/
@Override
public Builder links(Set<Link> links) {
return Builder.class.cast(super.links(links));
}
/**
* {@inheritDoc}
*/
@Override
public Builder fromResource(Resource in) {
return Builder.class.cast(super.fromResource(in));
protected ConcreteBuilder self() {
return this;
}
}
@Nullable
private final String status;
@Nullable
private final Date updated;
@SerializedName("media-types")
@SerializedName(value="media-types")
@Nullable
private final Set<MediaType> mediaTypes;
protected ApiMetadata(String id, String name, Set<Link> links, Date updated, String status, Set<MediaType> mediaTypes) {
super(id, name, links);
this.status = status;
this.updated = updated;
this.mediaTypes = ImmutableSet.copyOf(checkNotNull(mediaTypes, "mediaTypes"));
protected ApiMetadata(Builder<?> builder) {
super(builder);
this.status = checkNotNull(builder.status, "status");
this.updated = checkNotNull(builder.updated, "updated");
this.mediaTypes = ImmutableSet.copyOf(checkNotNull(builder.mediaTypes, "mediaTypes"));
}
/**
*/
@Nullable
public String getStatus() {
return this.status;
}
/**
*/
@Nullable
public Date getUpdated() {
return this.updated;
}
/**
*/
@Nullable
public Set<MediaType> getMediaTypes() {
return Collections.unmodifiableSet(this.mediaTypes);
}
@ -154,10 +138,9 @@ public class ApiMetadata extends Resource {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
ApiMetadata that = ApiMetadata.class.cast(obj);
return Objects.equal(this.status, that.status)
return super.equals(that) && Objects.equal(this.status, that.status)
&& Objects.equal(this.updated, that.updated)
&& Objects.equal(this.mediaTypes, that.mediaTypes)
;
&& Objects.equal(this.mediaTypes, that.mediaTypes);
}
protected ToStringHelper string() {