Merge branch 'develop' of github.com:jdaggett/jclouds

* 'develop' of github.com:jdaggett/jclouds:
  Improved parsing tests
  Nova client changes for delegate APIs & misc cleanup
  FloatingIP and KeyPair additions
  SecurityGroup support
  Incremental support for Image, Flavor and Floating IPs
  Floating IP support
This commit is contained in:
Adrian Cole 2012-02-29 17:36:03 +02:00
commit d1305f3034
42 changed files with 3315 additions and 77 deletions

View File

@ -24,6 +24,10 @@ import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPClient;
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
import org.jclouds.openstack.nova.v1_1.features.KeyPairClient;
import org.jclouds.openstack.nova.v1_1.features.SecurityGroupClient;
import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
@ -62,4 +66,32 @@ public interface NovaAsyncClient {
FlavorClient getFlavorClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides asynchronous access to Image features.
*/
@Delegate
ImageClient getImageClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides asynchronous access to Floating IP features.
*/
@Delegate
FloatingIPClient getFloatingIPClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides asynchronous access to Security Group features.
*/
@Delegate
SecurityGroupClient getSecurityGroupClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides asynchronous access to Key Pair features.
*/
@Delegate
KeyPairClient getKeyPairClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
}

View File

@ -26,6 +26,10 @@ import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPClient;
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
import org.jclouds.openstack.nova.v1_1.features.KeyPairClient;
import org.jclouds.openstack.nova.v1_1.features.SecurityGroupClient;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
@ -64,4 +68,32 @@ public interface NovaClient {
FlavorClient getFlavorClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides synchronous access to Image features.
*/
@Delegate
ImageClient getImageClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides synchronous access to Floating IP features.
*/
@Delegate
FloatingIPClient getFloatingIPClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides synchronous access to Security Group features.
*/
@Delegate
SecurityGroupClient getSecurityGroupClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
/**
* Provides synchronous access to Key Pair features.
*/
@Delegate
KeyPairClient getKeyPairClientForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
}

View File

@ -30,6 +30,14 @@ import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.features.FlavorAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.FloatingIPClient;
import org.jclouds.openstack.nova.v1_1.features.ImageAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
import org.jclouds.openstack.nova.v1_1.features.KeyPairAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.KeyPairClient;
import org.jclouds.openstack.nova.v1_1.features.SecurityGroupAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.SecurityGroupClient;
import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient;
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
import org.jclouds.openstack.nova.v1_1.handlers.NovaErrorHandler;
@ -50,6 +58,10 @@ public class NovaRestClientModule extends RestClientModule<NovaClient, NovaAsync
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
.put(ServerClient.class, ServerAsyncClient.class)//
.put(FlavorClient.class, FlavorAsyncClient.class)
.put(ImageClient.class, ImageAsyncClient.class)
.put(FloatingIPClient.class, FloatingIPAsyncClient.class)
.put(SecurityGroupClient.class, SecurityGroupAsyncClient.class)
.put(KeyPairClient.class, KeyPairAsyncClient.class)
.build();
public NovaRestClientModule() {

View File

@ -0,0 +1,166 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.domain;
import static com.google.common.base.Objects.toStringHelper;
import org.jclouds.javax.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
/**
* A Floating IP is an IP address that can be created and associated with a Server instance.
* Floating IPs can also be disassociated and deleted from a Server instance.
*
* @author Jeremy Daggett
* @author chamerling
*/
public class FloatingIP implements Comparable<FloatingIP> {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromFloatingIp(this);
}
public static class Builder {
private String id;
private String ip;
private String fixedIp;
private String instanceId;
public Builder id(String id) {
this.id = id;
return this;
}
public Builder ip(String ip) {
this.ip = ip;
return this;
}
public Builder fixedIp(String fixedIp) {
this.fixedIp = fixedIp;
return this;
}
public Builder instanceId(String instanceId) {
this.instanceId = instanceId;
return this;
}
public FloatingIP build() {
return new FloatingIP(id, ip, fixedIp, instanceId);
}
public Builder fromFloatingIp(FloatingIP in) {
return id(in.getId()).ip(in.getIp()).fixedIp(in.getFixedIp())
.instanceId(in.getInstanceId());
}
}
private String id;
private String ip;
@SerializedName("fixed_ip")
private String fixedIp;
@SerializedName("instance_id")
private String instanceId;
protected FloatingIP(String id, String ip, @Nullable String fixedIp,
@Nullable String instanceId) {
this.id = id;
this.ip = ip;
this.fixedIp = fixedIp;
this.instanceId = instanceId;
}
public String getId() {
return this.id;
}
public String getIp() {
return this.ip;
}
public String getFixedIp() {
return this.fixedIp;
}
public String getInstanceId() {
return this.fixedIp;
}
@Override
public int compareTo(FloatingIP o) {
return this.id.compareTo(o.getId());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((fixedIp == null) ? 0 : fixedIp.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result
+ ((instanceId == null) ? 0 : instanceId.hashCode());
result = prime * result + ((ip == null) ? 0 : ip.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
FloatingIP other = (FloatingIP) obj;
if (fixedIp == null) {
if (other.fixedIp != null)
return false;
} else if (!fixedIp.equals(other.fixedIp))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (instanceId == null) {
if (other.instanceId != null)
return false;
} else if (!instanceId.equals(other.instanceId))
return false;
if (ip == null) {
if (other.ip != null)
return false;
} else if (!ip.equals(other.ip))
return false;
return true;
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("ip", ip)
.add("fixedIp", fixedIp).add("instanceId", instanceId).toString();
}
}

View File

@ -0,0 +1,241 @@
/**
* 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.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.collect.Maps;
import com.google.gson.annotations.SerializedName;
/**
* An image is a collection of files you use to create or rebuild a server.
* Operators provide pre-built OS images by default. You may also create custom
* images.
*
* @author Jeremy Daggett
* @see <a href=
* "http://docs.openstack.org/api/openstack-compute/1.1/content/Images-d1e4427.html"
* />
*/
public class Image extends Resource {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromImage(this);
}
public static class Builder extends Resource.Builder {
private Date updated;
private Date created;
private String tenantId;
private String userId;
private ImageStatus status;
private int progress;
private int minDisk;
private int minRam;
private Resource server;
private Map<String, String> metadata = Maps.newHashMap();
public Builder updated(Date updated) {
this.updated = updated;
return this;
}
public Builder created(Date created) {
this.created = created;
return this;
}
public Builder tenantId(String tenantId) {
this.tenantId = tenantId;
return this;
}
public Builder userId(String userId) {
this.userId = userId;
return this;
}
public Builder status(ImageStatus status) {
this.status = status;
return this;
}
public Builder progress(int progress) {
this.progress = progress;
return this;
}
public Builder minDisk(int minDisk) {
this.minDisk = minDisk;
return this;
}
public Builder minRam(int minRam) {
this.minRam = minRam;
return this;
}
public Builder server(Resource server) {
this.server = server;
return this;
}
public Builder metadata(Map<String, String> metadata) {
this.metadata = metadata;
return this;
}
public Image build() {
return new Image(id, name, links, updated, created, tenantId, userId,
status, progress, minDisk, minRam, server, metadata);
}
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());
}
/**
* {@inheritDoc}
*/
@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));
}
}
private Date updated;
private Date created;
@SerializedName("tenant_id")
private String tenantId;
@SerializedName("user_id")
private String userId;
private ImageStatus status;
private int progress;
private int minDisk;
private int minRam;
private Resource server;
private Map<String, String> metadata = Maps.newHashMap();
protected Image(String id, String name, Set<Link> links, Date updated,
Date created, String tenantId, String userId, ImageStatus 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 = metadata;
}
public Date getUpdated() {
return this.updated;
}
public Date getCreated() {
return this.created;
}
public String getTenantId() {
return this.tenantId;
}
public String getUserId() {
return this.userId;
}
public ImageStatus getStatus() {
return this.status;
}
public int getProgress() {
return this.progress;
}
public int getMinDisk() {
return this.minDisk;
}
public int getMinRam() {
return this.minRam;
}
public Resource getServer() {
return this.server;
}
public Map<String, String> getMetadata() {
return this.metadata;
}
@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();
}
}

View File

@ -0,0 +1,47 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.domain;
/**
* In-flight images will have the status attribute set to SAVING and the
* conditional progress element (0-100% completion) will also be returned. Other
* possible values for the status attribute include: UNKNOWN, ACTIVE, SAVING,
* ERROR, and DELETED. Images with an ACTIVE status are available for install.
* The optional minDisk and minRam attributes set the minimum disk and RAM
* requirements needed to create a server with the image.
*
* @author Adrian Cole
*/
public enum ImageStatus {
UNRECOGNIZED, UNKNOWN, ACTIVE, SAVING, ERROR, DELETED;
public String value() {
return name();
}
public static ImageStatus fromValue(String v) {
try {
return valueOf(v);
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}

View File

@ -0,0 +1,125 @@
/**
* 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.Objects.toStringHelper;
import org.jclouds.javax.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
public class KeyPair {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromKeyPair(this);
}
public static class Builder {
private String publicKey;
private String privateKey;
private String userId;
private String name;
private String fingerprint;
public Builder publicKey(String publicKey) {
this.publicKey = publicKey;
return this;
}
public Builder privateKey(String privateKey) {
this.privateKey = privateKey;
return this;
}
public Builder userId(String userId) {
this.userId = userId;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder fingerprint(String fingerprint) {
this.fingerprint = fingerprint;
return this;
}
public KeyPair build() {
return new KeyPair(publicKey, privateKey, userId, name, fingerprint);
}
public Builder fromKeyPair(KeyPair in) {
return publicKey(in.getPublicKey()).privateKey(in.getPrivateKey())
.userId(in.getUserId()).name(in.getName())
.fingerprint(in.getFingerprint());
}
}
@SerializedName("public_key")
String publicKey;
@SerializedName("private_key")
String privateKey;
@SerializedName("user_id")
String userId;
String name;
String fingerprint;
protected KeyPair(String publicKey, String privateKey,
@Nullable String userId, String name, String fingerprint) {
this.publicKey = publicKey;
this.privateKey = privateKey;
this.userId = userId;
this.name = name;
this.fingerprint = fingerprint;
}
public String getPublicKey() {
return this.publicKey;
}
public String getPrivateKey() {
return this.privateKey;
}
public String getUserId() {
return this.privateKey;
}
public String getName() {
return this.name;
}
public String getFingerprint() {
return this.fingerprint;
}
@Override
public String toString() {
return toStringHelper("").add("publicKey", publicKey)
.add("privateKey", privateKey).add("userId", userId)
.add("name", name).add("fingerprint", fingerprint).toString();
}
}

View File

@ -0,0 +1,37 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.domain;
/**
*
* @author Adrian Cole
*/
public enum RebootType {
HARD, SOFT;
public String value() {
return name();
}
public static RebootType fromValue(String v) {
return valueOf(v);
}
}

View File

@ -0,0 +1,181 @@
/**
* 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.Objects.toStringHelper;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
/**
* Defines a security group
*
*/
public class SecurityGroup {
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromSecurityGroup(this);
}
public static class Builder {
private String id;
private String tenantId;
private String name;
private String description;
private Set<SecurityGroupRule> rules;
public Builder id(String id) {
this.id = id;
return this;
}
public Builder tenantId(String tenantId) {
this.tenantId = tenantId;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder description(String description) {
this.description = description;
return this;
}
public Builder rules(Set<SecurityGroupRule> rules) {
this.rules = rules;
return this;
}
public SecurityGroup build() {
return new SecurityGroup(id, tenantId, name, description, rules);
}
public Builder fromSecurityGroup(SecurityGroup in) {
return id(in.getId()).tenantId(in.getTenantId()).name(in.getName())
.description(in.getDescription()).rules(in.getRules());
}
}
protected String id;
@SerializedName("tenant_id")
protected String tenantId;
protected String name;
protected String description;
protected Set<SecurityGroupRule> rules;
protected SecurityGroup(String id, String tenantId, @Nullable String name,
@Nullable String description, Set<SecurityGroupRule> rules) {
this.id = id;
this.tenantId = tenantId;
this.name = name;
this.description = description;
}
public String getId() {
return this.id;
}
public String getTenantId() {
return this.tenantId;
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public Set<SecurityGroupRule> getRules() {
return this.rules;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((description == null) ? 0 : description.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((rules == null) ? 0 : rules.hashCode());
result = prime * result + ((tenantId == null) ? 0 : tenantId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SecurityGroup other = (SecurityGroup) obj;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (rules == null) {
if (other.rules != null)
return false;
} else if (!rules.equals(other.rules))
return false;
if (tenantId == null) {
if (other.tenantId != null)
return false;
} else if (!tenantId.equals(other.tenantId))
return false;
return true;
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("name", name)
.add("tenantId", tenantId).add("description", description).add("rules", rules)
.toString();
}
}

View File

@ -0,0 +1,251 @@
/**
* 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.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import com.google.gson.annotations.SerializedName;
/**
* Defines a security group rule
*
*/
public class SecurityGroupRule implements Comparable<SecurityGroupRule> {
public static enum IpProtocol {
TCP, UDP, ICMP, UNRECOGNIZED;
public String value() {
return name().toLowerCase();
}
@Override
public String toString() {
return value();
}
public static IpProtocol fromValue(String protocol) {
try {
return valueOf(checkNotNull(protocol, "protocol").toUpperCase());
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().fromSecurityGroupRule(this);
}
public static class Builder {
private String id;
private int fromPort;
private Map<String, String> group;
// tcp/udp/icmp - move to enum
private IpProtocol ipProtocol;
private int toPort;
private String parentGroupId;
private Map<String, String> ipRange;
public Builder id(String id) {
this.id = id;
return this;
}
public Builder fromPort(int fromPort) {
this.fromPort = fromPort;
return this;
}
public Builder group(Map<String, String> group) {
this.group = group;
return this;
}
public Builder ipProtocol(IpProtocol ipProtocol) {
this.ipProtocol = ipProtocol;
return this;
}
public Builder toPort(int toPort) {
this.toPort = toPort;
return this;
}
public Builder parentGroupId(String parentGroupId) {
this.parentGroupId = parentGroupId;
return this;
}
public Builder ipRange(Map<String, String> ipRange) {
this.ipRange = ipRange;
return this;
}
public SecurityGroupRule build() {
return new SecurityGroupRule(id, fromPort, group, ipProtocol, toPort,
parentGroupId, ipRange);
}
public Builder fromSecurityGroupRule(SecurityGroupRule in) {
return id(in.getId()).fromPort(in.getFromPort()).group(in.getGroup())
.ipProtocol(in.getIpProtocol()).toPort(in.getToPort()).parentGroupId(in.getParentGroupId())
.ipRange(in.getIpRange());
}
}
protected String id;
@SerializedName(value = "from_port")
protected int fromPort;
protected Map<String, String> group;
@SerializedName(value = "ip_protocol")
// tcp/udp/icmp
protected IpProtocol ipProtocol;
@SerializedName(value = "to_port")
protected int toPort;
@SerializedName(value = "parent_group_id")
protected String parentGroupId;
@SerializedName(value = "ip_range")
protected Map<String, String> ipRange;
protected SecurityGroupRule(String id, int fromPort, Map<String, String> group,
IpProtocol ipProtocol, int toPort, String parentGroupId, Map<String, String> ipRange) {
this.id = id;
this.fromPort = fromPort;
this.group = group;
this.ipProtocol = ipProtocol;
this.toPort = toPort;
this.parentGroupId = parentGroupId;
this.ipRange = ipRange;
}
public String getId() {
return this.id;
}
public int getFromPort() {
return this.fromPort;
}
public Map<String, String> getGroup() {
return this.group;
}
public IpProtocol getIpProtocol() {
return this.ipProtocol;
}
public int getToPort() {
return this.toPort;
}
public String getParentGroupId() {
return this.parentGroupId;
}
public Map<String, String> getIpRange() {
return this.ipRange;
}
@Override
public int compareTo(SecurityGroupRule o) {
return this.id.compareTo(o.getId());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + fromPort;
result = prime * result + ((group == null) ? 0 : group.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result
+ ((ipProtocol == null) ? 0 : ipProtocol.hashCode());
result = prime * result + ((ipRange == null) ? 0 : ipRange.hashCode());
result = prime * result
+ ((parentGroupId == null) ? 0 : parentGroupId.hashCode());
result = prime * result + toPort;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SecurityGroupRule other = (SecurityGroupRule) obj;
if (fromPort != other.fromPort)
return false;
if (group == null) {
if (other.group != null)
return false;
} else if (!group.equals(other.group))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (ipProtocol != other.ipProtocol)
return false;
if (ipRange == null) {
if (other.ipRange != null)
return false;
} else if (!ipRange.equals(other.ipRange))
return false;
if (parentGroupId == null) {
if (other.parentGroupId != null)
return false;
} else if (!parentGroupId.equals(other.parentGroupId))
return false;
if (toPort != other.toPort)
return false;
return true;
}
@Override
public String toString() {
return toStringHelper("").add("id", id).add("fromPort", fromPort)
.add("group", group).add("ipProtocol", ipProtocol)
.add("toPort", toPort).add("parentGroupId", parentGroupId)
.add("ipRange", ipRange).toString();
}
}

View File

@ -21,6 +21,7 @@ package org.jclouds.openstack.nova.v1_1.domain;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date;
import java.util.Map;
import java.util.Set;
@ -29,14 +30,17 @@ import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Address.Type;
import org.jclouds.util.Multimaps2;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.gson.annotations.SerializedName;
/**
* A server is a virtual machine instance in the compute system. Flavor and image are requisite
* elements when creating a server.
* A server is a virtual machine instance in the compute system. Flavor and
* image are requisite elements when creating a server.
*
* @author Adrian Cole
* @see <a href=
@ -53,13 +57,124 @@ public class Server extends Resource {
}
public static class Builder extends Resource.Builder {
private Multimap<Address.Type, Address> addresses = LinkedHashMultimap.create();
private String tenantId;
private String userId;
private Date updated;
private Date created;
private String hostId;
private String accessIPv4;
private String accessIPv6;
private ServerStatus status;
private int progress;
private Resource image;
private Resource flavor;
private Map<String, String> metadata = Maps.newHashMap();
// TODO: get gson multimap ad
private Multimap<Address.Type, Address> addresses = LinkedHashMultimap
.create();
/**
* @see Server#getTenantId()
*/
public Builder tenantId(String tenantId) {
this.tenantId = tenantId;
return this;
}
/**
* @see Server#getUserId()
*/
public Builder userId(String userId) {
this.userId = userId;
return this;
}
/**
* @see Server#getUpdated()
*/
public Builder updated(Date updated) {
this.updated = updated;
return this;
}
/**
* @see Server#getCreated()
*/
public Builder created(Date created) {
this.created = created;
return this;
}
/**
* @see Server#getHostId()
*/
public Builder hostId(String hostId) {
this.hostId = hostId;
return this;
}
/**
* @see Server#getAccessIPv4()
*/
public Builder accessIPv4(String accessIPv4) {
this.accessIPv4 = accessIPv4;
return this;
}
/**
* @see Server#getAccessIPv6()
*/
public Builder accessIPv6(String accessIPv6) {
this.accessIPv6 = accessIPv6;
return this;
}
/**
* @see Server#getStatus()
*/
public Builder status(ServerStatus status) {
this.status = status;
return this;
}
/**
* @see Server#getProgress()
*/
public Builder progress(int progress) {
this.progress = progress;
return this;
}
/**
* @see Server#getImage()
*/
public Builder image(Resource image) {
this.image = image;
return this;
}
/**
* @see Server#getImage()
*/
public Builder 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<Address.Type, Address> addresses) {
this.addresses = ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses"));
this.addresses = ImmutableMultimap.copyOf(checkNotNull(addresses,
"addresses"));
return this;
}
@ -67,15 +182,16 @@ public class Server extends Resource {
* @see Server#getPrivateAddresses()
*/
public Builder privateAddresses(Address... privateAddresses) {
return privateAddresses(ImmutableSet.copyOf(checkNotNull(privateAddresses, "privateAddresses")));
return privateAddresses(ImmutableSet.copyOf(checkNotNull(
privateAddresses, "privateAddresses")));
}
/**
* @see Server#getPrivateAddresses()
*/
public Builder privateAddresses(Set<Address> privateAddresses) {
this.addresses.replaceValues(Address.Type.PRIVATE, ImmutableSet.copyOf(checkNotNull(privateAddresses,
"privateAddresses")));
this.addresses.replaceValues(Address.Type.PRIVATE, ImmutableSet
.copyOf(checkNotNull(privateAddresses, "privateAddresses")));
return this;
}
@ -83,20 +199,24 @@ public class Server extends Resource {
* @see Server#getPublicAddresses()
*/
public Builder publicAddresses(Address... publicAddresses) {
return publicAddresses(ImmutableSet.copyOf(checkNotNull(publicAddresses, "publicAddresses")));
return publicAddresses(ImmutableSet.copyOf(checkNotNull(
publicAddresses, "publicAddresses")));
}
/**
* @see Server#getPublicAddresses()
*/
public Builder publicAddresses(Set<Address> publicAddresses) {
this.addresses.replaceValues(Address.Type.PUBLIC, ImmutableSet.copyOf(checkNotNull(publicAddresses,
"publicAddresses")));
this.addresses.replaceValues(Address.Type.PUBLIC, ImmutableSet
.copyOf(checkNotNull(publicAddresses, "publicAddresses")));
return this;
}
public Server build() {
return new Server(id, name, links, addresses);
// return new Server(id, name, links, addresses);
return new Server(id, name, links, tenantId, userId, updated,
created, hostId, accessIPv4, accessIPv6, status, progress,
image, flavor, addresses, metadata);
}
public Builder fromServer(Server in) {
@ -136,12 +256,98 @@ public class Server extends Resource {
}
}
@SerializedName("tenant_id")
protected String tenantId;
@SerializedName("user_id")
protected String userId;
protected Date updated;
protected Date created;
protected String hostId;
protected String accessIPv4;
protected String accessIPv6;
protected ServerStatus status;
protected int progress;
protected Resource image;
protected Resource flavor;
// TODO: get gson multimap adapter!
protected final Map<Address.Type, Set<Address>> addresses;
protected Map<String, String> metadata;
protected String adminPass;
protected Server(String id, String name, Set<Link> links, Multimap<Address.Type, Address> addresses) {
protected Server(String id, String name, Set<Link> links, String tenantId,
String userId, Date updated, Date created, String hostId,
String accessIPv4, String accessIPv6, ServerStatus status,
int progress, Resource image, Resource flavor,
Multimap<Address.Type, Address> addresses, Map<String, String> metadata) {
super(id, name, links);
this.addresses = Multimaps2.toOldSchool(ImmutableMultimap.copyOf(checkNotNull(addresses, "addresses")));
this.tenantId = tenantId;
this.userId = userId;
this.updated = updated;
this.created = created;
this.hostId = hostId;
this.accessIPv4 = accessIPv4;
this.accessIPv6 = accessIPv6;
this.status = status;
this.progress = progress;
this.image = image;
this.flavor = flavor;
this.metadata = Maps.newHashMap(metadata);
this.addresses = Multimaps2.toOldSchool(ImmutableMultimap
.copyOf(checkNotNull(addresses, "addresses")));
}
public String getTenantId() {
return this.tenantId;
}
public String getUserId() {
return this.userId;
}
public Date getUpdated() {
return this.updated;
}
public Date getCreated() {
return this.created;
}
public String getHostId() {
return this.hostId;
}
public String getAccessIPv4() {
return this.accessIPv4;
}
public String getAccessIPv6() {
return this.accessIPv6;
}
public ServerStatus getStatus() {
return this.status;
}
public int getProgress() {
return this.progress;
}
public Resource getImage() {
return this.image;
}
public Resource getFlavor() {
return this.flavor;
}
public Map<String, String> getMetadata() {
return this.metadata;
}
public String getAdminPass() {
return this.adminPass;
}
/**
@ -167,8 +373,14 @@ public class Server extends Resource {
@Override
public String toString() {
return toStringHelper("").add("id", id).add("name", name).add("links", links).add("addresses", addresses)
.toString();
return toStringHelper("").add("id", id).add("name", name)
.add("tenantId", tenantId).add("userId", userId).add("hostId", hostId)
.add("updated", updated).add("created", created)
.add("accessIPv4", accessIPv4).add("accessIPv6", accessIPv6)
.add("status", status).add("progress", progress)
.add("image", image).add("flavor", flavor)
.add("metadata", metadata)
.add("links", links).add("addresses", addresses).toString();
}
}

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.domain;
/**
* Servers contain a status attribute that can be used as an indication of the
* current server state. Servers with an ACTIVE status are available for use.
*
* Other possible values for the status attribute include: BUILD, REBUILD,
* SUSPENDED, RESIZE, VERIFY_RESIZE, REVERT_RESIZE, PASSWORD, REBOOT,
* HARD_REBOOT, DELETED, UNKNOWN, and ERROR.
*
* @author Adrian Cole
*/
public enum ServerStatus {
ACTIVE, BUILD, REBUILD, SUSPENDED, RESIZE, VERIFY_RESIZE, REVERT_RESIZE, PASSWORD, REBOOT, HARD_REBOOT, DELETED, UNKNOWN, ERROR, UNRECOGNIZED;
public String value() {
return name();
}
public static ServerStatus fromValue(String v) {
try {
return valueOf(v);
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}

View File

@ -23,17 +23,15 @@ import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.Flavor;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding;
/**
* Provides asynchronous access to Flavors via their REST API.
* <p/>
*
* @see FlavorClient
* @see <a href="http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
* @see <a href=
* "http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
* />
* @author Jeremy Daggett
*/
@ -59,7 +57,7 @@ public interface FlavorClient {
*
* @param id
* id of the flavor
* @return flavorr or null if not found
* @return flavor or null if not found
*/
Flavor getFlavor(String id);

View File

@ -0,0 +1,121 @@
/**
* 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.features;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
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.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Floating IPs via the REST API.
* <p/>
*
* @see FloatingIPClient
* @author Jeremy Daggett
*/
@SkipEncoding({ '/', '=' })
@RequestFilters(AuthenticateRequest.class)
public interface FloatingIPAsyncClient {
/**
* @see FloatingIPClient#listFloatingIPs
*/
@GET
@Path("/os-floating-ips")
@SelectJson("floating_ips")
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<FloatingIP>> listFloatingIPs();
/**
* @see FloatingIPClient#getFloatingIP
*/
@GET
@Path("/os-floating-ips/{id}")
@SelectJson("floating_ip")
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<FloatingIP> getFloatingIP(@PathParam("id") String id);
/**
* @see FloatingIPClient#allocate
*/
@POST
@Path("/os-floating-ips")
@SelectJson("floating_ip")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Payload("{}")
ListenableFuture<FloatingIP> allocate();
/**
* @see FloatingIPClient#deallocate
*/
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("/os-floating-ips/{id}")
ListenableFuture<Void> deallocate(@PathParam("id") String id);
/**
* @see FloatingIPClient#addFloatingIP
*/
@POST
@Path("/servers/{server}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"addFloatingIp\":%7B\"server\":\"{server}\",\"address\":\"{address}\"%7D%7D")
ListenableFuture<Void> addFloatingIP(
@PayloadParam("server") String serverId,
@PayloadParam("address") String address);
/**
* @see FloatingIPClient#removeFloatingIP
*/
@POST
@Path("/servers/{server}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"removeFloatingIp\":%7B\"server\":\"{server}\",\"address\":\"{address}\"%7D%7D")
ListenableFuture<Void> removeFloatingIP(
@PayloadParam("server") String serverId,
@PayloadParam("address") String address);
}

View File

@ -0,0 +1,89 @@
/**
* 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.features;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
/**
* Provides synchronous access to Floating IPs.
* <p/>
*
* @see FloatingIPAsyncClient
* @author Jeremy Daggett
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface FloatingIPClient {
/**
* List all Floating IP addresses
*
* @return all Floating IPs
*/
Set<FloatingIP> listFloatingIPs();
/**
* Get a specific Floating IP address
*
* @return all Floating IPs
*/
FloatingIP getFloatingIP(String id);
/**
* Allocate a Floating IP address
*
* @return a newly allocated FloatingIP
*/
FloatingIP allocate();
/**
* Deallocate a Floating IP address
*
* @param id
* the Floating IP id
*/
void deallocate(String id);
/**
* Add a Floating IP address to a Server
*
* @param serverId
* the serverId
* @param address
* the IP address to add
*
* NOTE: Possibly move this to ServerClient?
*/
void addFloatingIP(String serverId, String address);
/**
* Remove a Floating IP address from a Server
*
* @param serverId
* the serverId
* @param address
* the IP address to remove
*
* NOTE: Possibly move this to ServerClient?
*/
void removeFloatingIP(String serverId, String address);
}

View File

@ -0,0 +1,93 @@
/**
* 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.features;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
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.domain.Resource;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.Image;
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 org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Images via the REST API.
* <p/>
*
* @see ImageClient
* @author Jeremy Daggett
*/
@SkipEncoding({ '/', '=' })
@RequestFilters(AuthenticateRequest.class)
public interface ImageAsyncClient {
/**
* @see ImageClient#listImages
*/
@GET
@SelectJson("images")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Resource>> listImages();
/**
* @see ImageClient#listImagesInDetail
*/
@GET
@SelectJson("images")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images/detail")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Image>> listImagesInDetail();
/**
* @see ImageClient#getImage
*/
@GET
@SelectJson("flavor")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images/{id}")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Image> getImage(@PathParam("id") String id);
/**
* @see ImageClient#deleteImage
*/
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
@Path("/images/{id}")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteImage(@PathParam("id") String id);
}

View File

@ -0,0 +1,71 @@
/**
* 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.features;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Image;
/**
* Provides synchronous access to Images.
* <p/>
*
* @see ImageAsyncClient
* @see <a href="http://docs.openstack.org/api/openstack-compute/1.1/content/Servers-d1e2073.html"
* />
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface ImageClient {
/**
* List all images (IDs, names, links)
*
* @return all images (IDs, names, links)
*/
Set<Resource> listImages();
/**
* List all images (all details)
*
* @return all images (all details)
*/
Set<Image> listImagesInDetail();
/**
* List details of the specified image
*
* @param id
* id of the server
* @return server or null if not found
*/
Image getImage(String id);
/**
* Delete the specified image
*
* @param id id of the image
* @return server or null if not found
*/
void deleteImage(String id);
}

View File

@ -0,0 +1,88 @@
/**
* 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.features;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
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.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Key Pairs via the REST API.
* <p/>
*
* @see KeyPairClient
* @author Jeremy Daggett
*/
@SkipEncoding({ '/', '=' })
@RequestFilters(AuthenticateRequest.class)
public interface KeyPairAsyncClient {
@GET
@Path("/os-keypairs")
@SelectJson("keypairs")
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Map<String, KeyPair>>> listKeyPairs();
@POST
@Path("/os-keypairs")
@SelectJson("keypair")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"keypair\":%7B\"name\":\"{name}\"%7D%7D")
ListenableFuture<KeyPair> createKeyPair(@PayloadParam("name") String name);
@POST
@Path("/os-keypairs")
@SelectJson("keypair")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"keypair\":%7B\"name\":\"{name}\",\"public_key\":\"{publicKey}\"%7D%7D")
ListenableFuture<KeyPair> createKeyPairWithPublicKey(@PayloadParam("name") String name,
@PayloadParam("publicKey") String publicKey);
@DELETE
@Path("/os-keypairs/{name}")
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
@Consumes
ListenableFuture<Boolean> deleteKeyPair(@PathParam("name") String name);
}

View File

@ -0,0 +1,66 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.features;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
/**
* Provides synchronous access to Security Groups.
* <p/>
*
* @see KeyPairAsyncClient
* @author Jeremy Daggett
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface KeyPairClient {
/**
* List all Key Pairs.
*
* @return all Key Pairs
*/
Set<Map<String,KeyPair>> listKeyPairs();
/**
* Create a Key Pair.
*
* @return a Key Pair
*/
KeyPair createKeyPair(String name);
/**
* Create a Key Pair with a public key.
*
* @return a Key Pair with a public key.
*/
KeyPair createKeyPairWithPublicKey(String name, String publicKey);
/**
* Delete a Key Pairs.
*
* @return
*/
Boolean deleteKeyPair(String name);
}

View File

@ -0,0 +1,86 @@
/**
* 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.features;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
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.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Security Groups via the REST API.
* <p/>
*
* @see SecurityGroupClient
* @author Jeremy Daggett
*/
@SkipEncoding({ '/', '=' })
@RequestFilters(AuthenticateRequest.class)
public interface SecurityGroupAsyncClient {
/**
* @see SecurityGroupClient#listSecurityGroups
*/
@GET
@SelectJson("security_groups")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/os-security-groups")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<SecurityGroup>> listSecurityGroups();
/**
* @see SecurityGroupClient#getSecurityGroup
*/
@GET
@Path("/os-security-groups/{id}")
@SelectJson("security_group")
@Consumes(MediaType.APPLICATION_JSON)
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<SecurityGroup> getSecurityGroup(@PathParam("id") String id);
/**
* @see SecurityGroupClient#createSecurityGroup
*/
@POST
@Path("/os-security-groups")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Payload("name {name}\n")
@Produces(MediaType.TEXT_PLAIN)
ListenableFuture<SecurityGroup> createSecurityGroup(@PayloadParam("name") String name);
}

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.features;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides synchronous access to Security Groups.
* <p/>
*
* @see SecurityGroupAsyncClient
* @author Jeremy Daggett
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface SecurityGroupClient {
/**
* List all Security Groups.
*
* @return all Floating IPs
*/
Set<SecurityGroup> listSecurityGroups();
/**
* Get a specific Security Group
*
* @return a specific Security Group
*/
SecurityGroup getSecurityGroup(String id);
/**
* Create a Security Group
*
* @return a new Security Group
*/
SecurityGroup createSecurityGroup(String name);
}

View File

@ -21,19 +21,32 @@ package org.jclouds.openstack.nova.v1_1.features;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.domain.RebootType;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.options.CreateServerOptions;
import org.jclouds.openstack.nova.v1_1.options.RebuildServerOptions;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.Unwrap;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
@ -81,4 +94,94 @@ public interface ServerAsyncClient {
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<Server> getServer(@PathParam("id") String id);
/**
* @see NovaClient#deleteServer
*/
@DELETE
@Consumes
@ExceptionParser(ReturnFalseOnNotFoundOr404.class)
@Path("/servers/{id}")
ListenableFuture<Boolean> deleteServer(@PathParam("id") String id);
/**
* @see NovaClient#rebootServer
*/
@POST
@Path("/servers/{id}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"reboot\":%7B\"type\":\"{type}\"%7D%7D")
ListenableFuture<Void> rebootServer(@PathParam("id") String id, @PayloadParam("type") RebootType rebootType);
/**
* @see NovaClient#resizeServer
*/
@POST
@Path("/servers/{id}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"resize\":%7B\"flavorId\":{flavorId}%7D%7D")
ListenableFuture<Void> resizeServer(@PathParam("id") String id, @PayloadParam("flavorId") String flavorId);
/**
* @see NovaClient#confirmResizeServer
*/
@POST
@Path("/servers/{id}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"confirmResize\":null}")
ListenableFuture<Void> confirmResizeServer(@PathParam("id") String id);
/**
* @see NovaClient#revertResizeServer
*/
@POST
@Path("/servers/{id}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("{\"revertResize\":null}")
ListenableFuture<Void> revertResizeServer(@PathParam("id") String id);
/**
* @see NovaClient#createServer
*/
@POST
@Unwrap
@Consumes(MediaType.APPLICATION_JSON)
@Path("/servers")
@MapBinder(CreateServerOptions.class)
ListenableFuture<Server> createServer(@PayloadParam("name") String name, @PayloadParam("imageRef") String imageRef,
@PayloadParam("flavorRef") String flavorRef, CreateServerOptions... options);
/**
* @see NovaClient#rebuildServer
*/
@POST
@Path("/servers/{id}/action")
@Consumes
@MapBinder(RebuildServerOptions.class)
ListenableFuture<Void> rebuildServer(@PathParam("id") String id, RebuildServerOptions... options);
/**
* @see NovaClient#changeAdminPass
*/
@POST
@Path("/servers/{id}/action")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"changePassword\":%7B\"adminPass\":\"{adminPass}\"%7D%7D")
ListenableFuture<Void> changeAdminPass(@PathParam("id") String id, @PayloadParam("adminPass") String adminPass);
/**
* @see NovaClient#renameServer
*/
@PUT
@Path("/servers/{id}")
@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Payload("%7B\"server\":%7B\"name\":\"{name}\"%7D%7D")
ListenableFuture<Void> renameServer(@PathParam("id") String id, @PayloadParam("name") String newName);
}

View File

@ -21,9 +21,30 @@ package org.jclouds.openstack.nova.v1_1.features;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
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.domain.Resource;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.domain.RebootType;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.options.CreateServerOptions;
import org.jclouds.openstack.nova.v1_1.options.RebuildServerOptions;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.Unwrap;
import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides synchronous access to Server.
@ -60,4 +81,50 @@ public interface ServerClient {
*/
Server getServer(String id);
/**
* @see NovaClient#createServer
*/
Server createServer(String name, String imageRef,
String flavorRef, CreateServerOptions... options);
/**
* @see NovaClient#deleteServer
*/
Boolean deleteServer(String id);
/**
* @see NovaClient#rebootServer
*/
void rebootServer(String id, RebootType rebootType);
/**
* @see NovaClient#resizeServer
*/
void resizeServer(String id, String flavorId);
/**
* @see NovaClient#confirmResizeServer
*/
void confirmResizeServer(String id);
/**
* @see NovaClient#revertResizeServer
*/
void revertResizeServer(String id);
/**
* @see NovaClient#rebuildServer
*/
void rebuildServer(String id, RebuildServerOptions... options);
/**
* @see NovaClient#changeAdminPass
*/
void changeAdminPass(String id, String adminPass);
/**
* @see NovaClient#renameServer
*/
void renameServer(String id, String newName);
}

View File

@ -0,0 +1,245 @@
/**
* 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.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.encryption.internal.Base64;
import org.jclouds.http.HttpRequest;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.rest.MapBinder;
import org.jclouds.rest.binders.BindToJsonPayload;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*
*/
public class CreateServerOptions implements MapBinder {
@Inject
private BindToJsonPayload jsonBinder;
static class File {
private final String path;
private final String contents;
public File(String path, byte[] contents) {
this.path = checkNotNull(path, "path");
this.contents = Base64.encodeBytes(checkNotNull(contents, "contents"));
checkArgument(path.getBytes().length < 255, String.format(
"maximum length of path is 255 bytes. Path specified %s is %d bytes", path, path.getBytes().length));
checkArgument(contents.length < 10 * 1024, String.format(
"maximum size of the file is 10KB. Contents specified is %d bytes", contents.length));
}
public String getContents() {
return contents;
}
public String getPath() {
return path;
}
}
@SuppressWarnings("unused")
private class ServerRequest {
final String name;
final String imageRef;
final String flavorRef;
String adminPass;
Map<String, String> metadata;
List<File> personality;
String key_name;
@SerializedName(value="security_groups")
Set<SecurityGroup> securityGroups;
private ServerRequest(String name, String imageRef, String flavorRef) {
this.name = name;
this.imageRef = imageRef;
this.flavorRef = flavorRef;
}
}
private Map<String, String> metadata = Maps.newHashMap();
private List<File> files = Lists.newArrayList();
private Set<String> securityGroups = Sets.newHashSet();
private String keyName;
private String adminPass;
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
ServerRequest server = new ServerRequest(checkNotNull(postParams.get("name"), "name parameter not present"),
checkNotNull(postParams.get("imageRef"), "imageRef parameter not present"), checkNotNull(postParams
.get("flavorRef"), "flavorRef parameter not present"));
if (metadata.size() > 0)
server.metadata = metadata;
if (files.size() > 0)
server.personality = files;
if (keyName != null)
server.key_name = keyName;
if (securityGroups.size() > 0) {
server.securityGroups = Sets.newHashSet();
for (String groupName : securityGroups) {
SecurityGroup group = SecurityGroup.builder().name(groupName).build();
server.securityGroups.add(group);
}
}
if (adminPass != null) {
server.adminPass = adminPass;
}
return bindToRequest(request, ImmutableMap.of("server", server));
}
/**
* You may further customize a cloud server by injecting data into the file system of the cloud
* server itself. This is useful, for example, for inserting ssh keys, setting configuration
* files, or storing data that you want to retrieve from within the instance itself. It is
* intended to provide a minimal amount of launch-time personalization. If significant
* customization is required, a custom image should be created. The max size of the file path
* data is 255 bytes while the max size of the file contents is 10KB. Note that the file contents
* should be encoded as a Base64 string and the 10KB limit refers to the number of bytes in the
* decoded data not the number of characters in the encoded data. The maximum number of file
* path/content pairs that can be supplied is 5. Any existing files that match the specified file
* will be renamed to include the extension bak followed by a time stamp. For example, the file
* /etc/passwd will be backed up as /etc/passwd.bak.1246036261.5785. All files will have root and
* the root group as owner and group owner, respectively and will allow user and group read
* access only (-r--r-----).
*/
public CreateServerOptions withFile(String path, byte[] contents) {
checkState(files.size() < 5, "maximum number of files allowed is 5");
files.add(new File(path, contents));
return this;
}
public CreateServerOptions withAdminPass(String adminPass) {
checkNotNull(adminPass, "adminPass");
this.adminPass = adminPass;
return this;
}
/**
* Custom cloud server metadata can also be supplied at launch time. This metadata is stored in
* the API system where it is retrievable by querying the API for server status. The maximum size
* of the metadata key and value is each 255 bytes and the maximum number of key-value pairs that
* can be supplied per server is 5.
*/
public CreateServerOptions withMetadata(Map<String, String> metadata) {
checkNotNull(metadata, "metadata");
checkArgument(metadata.size() <= 5, "you cannot have more then 5 metadata values. You specified: "
+ metadata.size());
for (Entry<String, String> entry : metadata.entrySet()) {
checkArgument(entry.getKey().getBytes().length < 255, String.format(
"maximum length of metadata key is 255 bytes. Key specified %s is %d bytes", entry.getKey(), entry
.getKey().getBytes().length));
checkArgument(entry.getKey().getBytes().length < 255, String.format(
"maximum length of metadata value is 255 bytes. Value specified for %s (%s) is %d bytes", entry
.getKey(), entry.getValue(), entry.getValue().getBytes().length));
}
this.metadata = metadata;
return this;
}
/**
* A keypair name can be defined when creating a server. This key will be
* linked to the server and used to SSH connect to the machine
*
* @param keyName
* @return
*/
public CreateServerOptions withKeyName(String keyName) {
checkNotNull(keyName, "keyName");
this.keyName = keyName;
return this;
}
/**
* Defines the security group name to be used when creating a server.
*
* @param groupName
* @return
*/
public CreateServerOptions withSecurityGroup(String groupName) {
checkNotNull(groupName, "groupName");
this.securityGroups.add(groupName);
return this;
}
public static class Builder {
/**
* @see CreateServerOptions#withFile(String,byte [])
*/
public static CreateServerOptions withFile(String path, byte[] contents) {
CreateServerOptions options = new CreateServerOptions();
return options.withFile(path, contents);
}
public static CreateServerOptions withAdminPass(String adminPass) {
CreateServerOptions options = new CreateServerOptions();
return options.withAdminPass(adminPass);
}
/**
* @see CreateServerOptions#withMetadata(Map<String, String>)
*/
public static CreateServerOptions withMetadata(Map<String, String> metadata) {
CreateServerOptions options = new CreateServerOptions();
return options.withMetadata(metadata);
}
/**
* @see CreateServerOptions#withKeyName(String)
*/
public static CreateServerOptions withKeyName(String keyName) {
CreateServerOptions options = new CreateServerOptions();
return options.withKeyName(keyName);
}
/**
* @see CreateServerOptions#withGroupName(String)
*/
public static CreateServerOptions withSecurityGroup(String name) {
CreateServerOptions options = new CreateServerOptions();
return options.withSecurityGroup(name);
}
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
return jsonBinder.bindToRequest(request, input);
}
}

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.options;
import java.util.Date;
import org.jclouds.openstack.options.BaseListOptions;
/**
* Options used to control the amount of detail in the request.
*
* @see BaseListOptions
* @see <a href="http://wiki.openstack.org/OpenStackAPI_1-1" />
* @author Adrian Cole
*/
public class ListOptions extends BaseListOptions {
public static final ListOptions NONE = new ListOptions();
/**
* unless used, only the name and id will be returned per row.
*
* @return
*/
public ListOptions withDetails() {
this.pathSuffix = "/detail";
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ListOptions changesSince(Date ifModifiedSince) {
super.changesSince(ifModifiedSince);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ListOptions maxResults(int limit) {
super.maxResults(limit);
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ListOptions startAt(long offset) {
super.startAt(offset);
return this;
}
public static class Builder {
/**
* @see ListOptions#withDetails()
*/
public static ListOptions withDetails() {
ListOptions options = new ListOptions();
return options.withDetails();
}
/**
* @see BaseListOptions#startAt(long)
*/
public static ListOptions startAt(long prefix) {
ListOptions options = new ListOptions();
return options.startAt(prefix);
}
/**
* @see BaseListOptions#maxResults(long)
*/
public static ListOptions maxResults(int maxKeys) {
ListOptions options = new ListOptions();
return options.maxResults(maxKeys);
}
/**
* @see BaseListOptions#changesSince(Date)
*/
public static ListOptions changesSince(Date since) {
ListOptions options = new ListOptions();
return options.changesSince(since);
}
}
}

View File

@ -0,0 +1,80 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.options;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
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.collect.ImmutableMap;
import com.google.common.collect.Maps;
/**
*
*
* @author Adrian Cole
*
*/
public class RebuildServerOptions implements MapBinder {
@Inject
private BindToJsonPayload jsonBinder;
String imageRef;
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
Map<String, String> image = Maps.newHashMap();
if (imageRef != null)
image.put("imageRef", imageRef);
return jsonBinder.bindToRequest(request, ImmutableMap.of("rebuild", image));
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
throw new IllegalStateException("RebuildServer is a POST operation");
}
/**
* @param ref
* - reference of the image to rebuild the server with.
*/
public RebuildServerOptions withImage(String ref) {
checkNotNull(ref, "image reference should not be null");
checkArgument(!ref.isEmpty(), "image reference should not be empty");
this.imageRef = ref;
return this;
}
public static class Builder {
/**
* @see RebuildServerOptions#withImage(String)
*/
public static RebuildServerOptions withImage(String ref) {
RebuildServerOptions options = new RebuildServerOptions();
return options.withImage(ref);
}
}
}

View File

@ -1,6 +1,7 @@
package org.jclouds.openstack.nova.v1_1.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.net.URI;
@ -21,56 +22,102 @@ import com.google.common.collect.ImmutableSet;
*
* @author Jeremy Daggett
*/
@Test(groups = "unit", testName = "FlavorAsyncClientTest")
@Test(groups = "unit", testName = "FlavorClientExpectTest")
public class FlavorClientExpectTest extends BaseNovaRestClientExpectTest {
public void testListFlavorsWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpRequest listFlavors = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/flavor_list.json")).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/flavor_list.json")).build();
NovaClient clientWhenFlavorsExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listServers, listFlavorsResponse);
NovaClient clientWhenFlavorsExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
listFlavors, listFlavorsResponse);
assertEquals(clientWhenFlavorsExist.getConfiguredRegions(), ImmutableSet.of("North"));
assertEquals(clientWhenFlavorsExist.getConfiguredRegions(),
ImmutableSet.of("North"));
assertEquals(clientWhenFlavorsExist.getFlavorClientForRegion("North").listFlavors().toString(),
new ParseFlavorListTest().expected().toString());
assertEquals(clientWhenFlavorsExist.getFlavorClientForRegion("North")
.listFlavors().toString(), new ParseFlavorListTest().expected()
.toString());
}
public void testListFlavorsWhenReponseIs404IsEmpty() throws Exception {
HttpRequest listFlavors = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpRequest listFlavors = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(404).build();
HttpResponse listFlavorsResponse = HttpResponse.builder().statusCode(404)
.build();
NovaClient clientWhenNoServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listFlavors, listFlavorsResponse);
NovaClient clientWhenNoServersExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
listFlavors, listFlavorsResponse);
assertTrue(clientWhenNoServersExist.getFlavorClientForRegion("North").listFlavors().isEmpty());
assertTrue(clientWhenNoServersExist.getFlavorClientForRegion("North")
.listFlavors().isEmpty());
}
// TODO: gson deserializer for Multimap
public void testGetFlavorWhenResponseIs2xx() throws Exception {
HttpRequest getFlavor = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors/foo")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse getFlavorResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/flavor_details.json")).build();
HttpRequest getFlavor = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors/52415800-8b69-11e0-9b19-734f1195ff37"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, getFlavor, getFlavorResponse);
HttpResponse getFlavorResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/flavor_details.json")).build();
NovaClient clientWhenFlavorsExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
getFlavor, getFlavorResponse);
assertEquals(clientWhenFlavorsExist.getFlavorClientForRegion("North")
.getFlavor("52415800-8b69-11e0-9b19-734f1195ff37").toString(),
new ParseFlavorTest().expected().toString());
}
public void testGetFlavorWhenResponseIs404() throws Exception {
HttpRequest getFlavor = HttpRequest
.builder()
.method("GET")
.endpoint(
URI.create("https://compute.north.host/v1.1/3456/flavors/123"))
.headers(
ImmutableMultimap.<String, String> builder()
.put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();
HttpResponse getFlavorResponse = HttpResponse.builder().statusCode(404)
.payload(payloadFromResource("/flavor_details.json")).build();
NovaClient clientWhenNoFlavorsExist = requestsSendResponses(
keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess,
getFlavor, getFlavorResponse);
assertNull(clientWhenNoFlavorsExist.getFlavorClientForRegion("North").getFlavor("123"));
assertEquals(clientWhenServersExist.getFlavorClientForRegion("North").getFlavor("foo").toString(),
new ParseFlavorTest().expected().toString());
}
}

View File

@ -36,7 +36,11 @@ import org.testng.annotations.Test;
@Test(groups = "live", testName = "FlavorClientLiveTest")
public class FlavorClientLiveTest extends BaseNovaClientLiveTest {
/**
* Tests the listing of Flavors (getFlavor() is tested too!)
*
* @throws Exception
*/
@Test
public void testListFlavors() throws Exception {
for (String regionId : context.getApi().getConfiguredRegions()) {
@ -53,4 +57,29 @@ public class FlavorClientLiveTest extends BaseNovaClientLiveTest {
}
}
/**
* Tests the listing of Flavors in detail (getFlavor() is tested too!)
*
* @throws Exception
*/
@Test
public void testListFlavorsInDetail() throws Exception {
for (String regionId : context.getApi().getConfiguredRegions()) {
FlavorClient client = context.getApi().getFlavorClientForRegion(regionId);
Set<Flavor> response = client.listFlavorsInDetail();
assert null != response;
assertTrue(response.size() >= 0);
for (Flavor flavor : response) {
Flavor newDetails = client.getFlavor(flavor.getId());
assertEquals(newDetails.getId(), flavor.getId());
assertEquals(newDetails.getName(), flavor.getName());
assertEquals(newDetails.getLinks(), flavor.getLinks());
assertEquals(newDetails.getRam(), flavor.getRam());
assertEquals(newDetails.getDisk(), flavor.getDisk());
assertEquals(newDetails.getVcpus(), flavor.getVcpus());
}
}
}
}

View File

@ -0,0 +1,59 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v1_1.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientLiveTest;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code ServerClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "FloatingIPClientLiveTest")
public class FloatingIPClientLiveTest extends BaseNovaClientLiveTest {
@Test
public void testListFloatingIPs() throws Exception {
for (String regionId : context.getApi().getConfiguredRegions()) {
FloatingIPClient client = context.getApi().getFloatingIPClientForRegion(regionId);
Set<FloatingIP> response = client.listFloatingIPs();
assert null != response;
assertTrue(response.size() >= 0);
for (FloatingIP ip : response) {
FloatingIP newDetails = client.getFloatingIP(ip.getId());
assertEquals(newDetails.getId(), ip.getId());
assertEquals(newDetails.getIp(), ip.getIp());
assertEquals(newDetails.getFixedIp(), ip.getFixedIp());
assertEquals(newDetails.getInstanceId(), ip.getInstanceId());
}
}
}
}

View File

@ -73,22 +73,4 @@ public class ServerClientExpectTest extends BaseNovaRestClientExpectTest {
assertTrue(clientWhenNoServersExist.getServerClientForRegion("North").listServers().isEmpty());
}
// TODO: gson deserializer for Multimap
public void testGetServerWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/servers/foo")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/server_details.json")).build();
NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
responseWithKeystoneAccess, listServers, listServersResponse);
assertEquals(clientWhenServersExist.getServerClientForRegion("North").getServer("foo").toString(),
new ParseServerTest().expected().toString());
}
}

View File

@ -0,0 +1,87 @@
/**
* 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.parse;
import java.net.URI;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.json.BaseSetParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
*
* @author Jeremy Daggett
*/
@Test(groups = "unit", testName = "ParseImageListTest")
public class ParseImageListTest extends BaseSetParserTest<Resource> {
@Override
public String resource() {
return "/image_list.json";
}
@Override
@SelectJson("images")
@Consumes(MediaType.APPLICATION_JSON)
public Set<Resource> expected() {
return ImmutableSet
.of(Resource
.builder()
.id("52415800-8b69-11e0-9b19-734f6f006e54")
.name("CentOS 5.2")
.links(
Link.create(
Relation.SELF,
URI.create("http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f6f006e54")),
Link.create(
Relation.BOOKMARK,
URI.create("http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f6f006e54")))
.build(),
Resource
.builder()
.id("52415800-8b69-11e0-9b19-734f5736d2a2")
.name("My Server Backup")
.links(
Link.create(
Relation.SELF,
URI.create("http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2")),
Link.create(
Relation.BOOKMARK,
URI.create("http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2")))
.build());
}
protected Injector injector() {
return Guice.createInjector(new NovaParserModule(), new GsonModule());
}
}

View File

@ -0,0 +1,104 @@
/**
* 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.parse;
import java.net.URI;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.openstack.nova.v1_1.domain.ImageStatus;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Jeremy Daggett
*/
@Test(groups = "unit", testName = "ParseImageTest")
public class ParseImageTest extends BaseItemParserTest<Image> {
@Override
public String resource() {
return "/image_details.json";
}
@Override
@SelectJson("image")
@Consumes(MediaType.APPLICATION_JSON)
public Image expected() {
return Image
.builder()
.id("52415800-8b69-11e0-9b19-734f5736d2a2")
.name("My Server Backup")
.updated(
new SimpleDateFormatDateService()
.iso8601SecondsDateParse("2010-10-10T12:00:00Z"))
.created(
new SimpleDateFormatDateService()
.iso8601SecondsDateParse("2010-08-10T12:00:00Z"))
.tenantId("12345")
.userId("joe")
.status(ImageStatus.SAVING)
.progress(80)
.minDisk(5)
.minRam(256)
.metadata(new ImmutableMap.Builder<String, String>()
.put("ImageType", "Gold")
.put("ImageVersion", "1.5").build())
.server(
Resource
.builder()
.id("52415800-8b69-11e0-9b19-734f335aa7b3")
.name("null")
.links(
Link.create(
Relation.SELF,
URI.create("http://servers.api.openstack.org/v1.1/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3")),
Link.create(
Relation.BOOKMARK,
URI.create("http://servers.api.openstack.org/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3")))
.build())
.links(
ImmutableSet.of(
Link.create(
Relation.SELF,
URI.create("http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2")),
Link.create(
Relation.BOOKMARK,
URI.create("http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"))))
.build();
}
protected Injector injector() {
return Guice.createInjector(new NovaParserModule(), new GsonModule());
}
}

View File

@ -18,17 +18,25 @@
*/
package org.jclouds.openstack.nova.v1_1.parse;
import java.net.URI;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.Address;
import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.ServerStatus;
import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
import com.google.inject.Injector;
@ -48,12 +56,56 @@ public class ParseServerTest extends BaseItemParserTest<Server> {
@Consumes(MediaType.APPLICATION_JSON)
public Server expected() {
return Server
.builder()
.id("52415800-8b69-11e0-9b19-734f000004d2")
.name("sample-server")
.publicAddresses(Address.createV4("67.23.10.132"), Address.createV6("::babe:67.23.10.132"),
Address.createV4("67.23.10.131"), Address.createV6("::babe:4317:0A83")).privateAddresses(
Address.createV4("10.176.42.16"), Address.createV6("::babe:10.176.42.16")).build();
.builder()
.id("52415800-8b69-11e0-9b19-734f000004d2")
.tenantId("1234")
.userId("5678")
.name("sample-server")
.updated(
new SimpleDateFormatDateService()
.iso8601SecondsDateParse("2010-10-10T12:00:00Z"))
.created(
new SimpleDateFormatDateService()
.iso8601SecondsDateParse("2010-08-10T12:00:00Z"))
.hostId("e4d909c290d0fb1ca068ffaddf22cbd0")
.accessIPv4("67.23.10.132")
.accessIPv6("::babe:67.23.10.132")
.status(ServerStatus.BUILD)
.progress(60)
.image(
Resource
.builder()
.id("52415800-8b69-11e0-9b19-734f6f006e54")
.name("null")
.links(
Link.create(
Relation.SELF,
URI.create("http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f6f006e54")),
Link.create(
Relation.BOOKMARK,
URI.create("http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f6f006e54")))
.build())
.flavor(Resource
.builder()
.id("52415800-8b69-11e0-9b19-734f216543fd")
.name("null")
.links(
Link.create(
Relation.SELF,
URI.create("http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd")),
Link.create(
Relation.BOOKMARK,
URI.create("http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd")))
.build())
.metadata(new ImmutableMap.Builder<String, String>()
.put("Server Label", "Web Head 1")
.put("Image Version", "2.1").build())
.publicAddresses(Address.createV4("67.23.10.132"),
Address.createV6("::babe:67.23.10.132"),
Address.createV4("67.23.10.131"),
Address.createV6("::babe:4317:0A83"))
.privateAddresses(Address.createV4("10.176.42.16"),
Address.createV6("::babe:10.176.42.16")).build();
}

View File

@ -0,0 +1,9 @@
{
"floating_ip" :
{
"id" : 1,
"ip" : "10.0.0.3",
"fixed_ip" : "10.0.0.2",
"instance_id" : 123
}
}

View File

@ -0,0 +1,16 @@
{
"floating_ips" : [
{
"instance_id": 12,
"ip" : "10.0.0.3",
"fixed_ip": "11.0.0.1",
"id" : 1
},
{
"instance_id": null,
"ip": "10.0.0.5",
"fixed_ip": null,
"id": 2
}
]
}

View File

@ -0,0 +1,41 @@
{
"image" : {
"id" : "52415800-8b69-11e0-9b19-734f5736d2a2",
"name" : "My Server Backup",
"updated" : "2010-10-10T12:00:00Z",
"created" : "2010-08-10T12:00:00Z",
"tenant_id" : "12345",
"user_id" : "joe",
"status" : "SAVING",
"progress" : 80,
"minDisk" : 5,
"minRam" : 256,
"metadata" : {
"ImageType" : "Gold",
"ImageVersion" : "1.5"
},
"server" : {
"id": "52415800-8b69-11e0-9b19-734f335aa7b3",
"links": [
{
"rel": "self",
"href": "http://servers.api.openstack.org/v1.1/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3"
},
{
"rel": "bookmark",
"href": "http://servers.api.openstack.org/1234/servers/52415800-8b69-11e0-9b19-734f335aa7b3"
}
]
},
"links": [
{
"rel" : "self",
"href" : "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
},
{
"rel" : "bookmark",
"href" : "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
}
]
}
}

View File

@ -0,0 +1,32 @@
{
"images": [
{
"id": "52415800-8b69-11e0-9b19-734f6f006e54",
"name": "CentOS 5.2",
"links": [
{
"rel": "self",
"href": "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
},
{
"rel": "bookmark",
"href": "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f6f006e54"
}
]
},
{
"id" : "52415800-8b69-11e0-9b19-734f5736d2a2",
"name" : "My Server Backup",
"links": [
{
"rel" : "self",
"href" : "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
},
{
"rel" : "bookmark",
"href" : "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f5736d2a2"
}
]
}
]
}

View File

@ -0,0 +1,9 @@
{
"keypair": {
"public_key": "ssh-rsa AAAXB3NzaC1yc2EAAAADAQABAAAAgQDFNyGjgs6c9akgmZ2ou/fJf7Pdrc23hC95/gM/33OrG4GZABACE4DTioa/PGN+7rHv9YUavUCtXrWayhGniKq/wCuI5fo5TO4AmDNv7/sCGHIHFumADSIoLx0vFhGJIetXEWxL9r0lfFC7//6yZM2W3KcGjbMtlPXqBT9K9PzdyQ== nova@nv-aw2az1-api0001\n",
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIAAAKBgQDFNyGjgs6c9akgmZ2ou/fJf7Pdrc23hC95/gM/33OrG4GZABAC\nE4DTioa/PGN+7rHv9YUavUCtXrWayhGniKq/wCuI5fo5TO4AmDNv7/sCGHIHFumA\nDSIoLx0vFhGJIetXEWxL9r0lfFC7//6yZM2W3KcGjbMtlPXqBT9K9PzdyQIDAQAB\nAoGAW8Ww+KbpQK8smcgCTr/RqcmsSI8VeL2hXjJvDq0L5WbyYuFdkanDvCztUVZn\nsmyfDtwAqZXB4Ct/dN1tY7m8QpdyRaKRW4Q+hghGCAQpsG7rYDdvwdEyvMaW5RA4\ntucQyajMNyQ/tozU3wMx/v8A7RvGcE9tqoG0WK1C3kBu95UCQQDrOd+joYDkvccz\nFIVu5gNPMXEh3fGGzDxk225UlvESquYLzfz4TfmuUjH4Z1BL3wRiwfJsrrjFkm33\njIidDE8PAkEA1qHjxuaIS1yz/rfzErmcOVNlbFHMP4ihjGTTvh1ZctXlNeLwzENQ\nEDaQV3IpUY1KQR6rxcWb5AXgfF9D9PYFpwJBANucAqGAbRgh3lJgPFtXP4u2O0tF\nLPOOxmvbOdybt6KYD4LB5AXmts77SlACFMNhCXUyYaT6UuOSXDyb5gfJsB0CQQC3\nFaGXKU9Z+doQjhlq/6mjvN/nZl80Uvh7Kgb1RVPoAU1kihGeLE0/h0vZTCiyyDNv\nGRqtucMg32J+tUTi0HpBAkAwHiCZMHMeJWHUwIwlRQY/dnR86FWobRl98ViF2rCL\nDHkDVOeIser3Q6zSqU5/m99lX6an5g8pAh/R5LqnOQZC\n-----END RSA PRIVATE KEY-----\n",
"user_id": "65649731189278",
"name": "testkeypair",
"fingerprint": "d2:1f:c9:2b:d8:90:77:5f:15:64:27:e3:9f:77:1d:e4"
}
}

View File

@ -0,0 +1,18 @@
{
"keypairs": [
{
"keypair": {
"public_key": "ssh-rsa AAAXB3NzaC1yc2EAAAADAQABAAAAgQCy9EC3O7Ff80vPEfAHDQob61PGwcpYc5KE7tEZnZhrB9n0NyHPRm0E0M+ls3fcTa04HDi+R0DzmRwoyhHQJyI658v8kWZZcuvFjKCcsgsSh/dzdX0xTreLIzSOzt5U7RnZYfshP5cmxtF99yrEY3M/swdin0L+fXsTSkR1B42STQ== nova@nv-aw2az1-api0001\n",
"name": "default",
"fingerprint": "ab:0c:f4:f3:54:c0:5d:3f:ed:62:ad:d3:94:7c:79:7c"
}
},
{
"keypair": {
"public_key": "ssh-rsa AAAXB3NzaC1yc2EAAAADAQABAAAAgQDFNyGjgs6c9akgmZ2ou/fJf7Pdrc23hC95/gM/33OrG4GZABACE4DTioa/PGN+7rHv9YUavUCtXrWayhGniKq/wCuI5fo5TO4AmDNv7/sCGHIHFumADSIoLx0vFhGJIetXEWxL9r0lfFC7//6yZM2W3KcGjbMtlPXqBT9K9PzdyQ== nova@nv-aw2az1-api0001\n",
"name": "testkeypair",
"fingerprint": "d2:1f:c9:2b:d8:90:77:5f:15:64:27:e3:9f:77:1d:e4"
}
}
]
}

View File

@ -0,0 +1,34 @@
{
"security_group":
{
"rules": [
{
"from_port": 22,
"group": {},
"ip_protocol": "tcp",
"to_port": 22,
"parent_group_id": 28,
"ip_range": {
"cidr": "10.2.6.0/24"
},
"id": 108
},
{
"from_port": 22,
"group": {
"tenant_id": "admin",
"name": "11111"
},
"ip_protocol": "tcp",
"to_port": 22,
"parent_group_id": 28,
"ip_range": {},
"id": 109
}
],
"tenant_id": "tenant0",
"id": 0,
"name": "name0",
"description": "description0"
}
}

View File

@ -0,0 +1,51 @@
{
"security_groups":[
{
"rules":[
{
"from_port":22,
"group":{
},
"ip_protocol":"tcp",
"to_port":22,
"parent_group_id":3,
"ip_range":{
"cidr":"0.0.0.0/0"
},
"id":107
},
{
"from_port":7600,
"group":{
},
"ip_protocol":"tcp",
"to_port":7600,
"parent_group_id":3,
"ip_range":{
"cidr":"0.0.0.0/0"
},
"id":118
},
{
"from_port":8084,
"group":{
},
"ip_protocol":"tcp",
"to_port":8084,
"parent_group_id":3,
"ip_range":{
"cidr":"0.0.0.0/0"
},
"id":119
}
],
"tenant_id":"tenant1",
"id":1,
"name":"name1",
"description":"description1"
}
]
}