From 602002660abb287d684e6a68d0ea5f908279e13a Mon Sep 17 00:00:00 2001 From: Adam Lowe Date: Mon, 9 Jan 2012 13:01:24 +0000 Subject: [PATCH 01/82] Improving javadocs for Archive, Domain, Email and Server GleSYS clients --- .../org/jclouds/glesys/domain/Archive.java | 5 +- .../org/jclouds/glesys/domain/Domain.java | 4 + .../jclouds/glesys/domain/DomainRecord.java | 19 +++++ .../java/org/jclouds/glesys/domain/Email.java | 9 ++ .../jclouds/glesys/domain/EmailOverview.java | 4 + .../glesys/domain/EmailOverviewDomain.java | 5 ++ .../glesys/domain/EmailOverviewSummary.java | 6 ++ .../jclouds/glesys/domain/ServerCreated.java | 19 +++-- .../jclouds/glesys/domain/ServerUptime.java | 3 + .../glesys/features/DomainAsyncClient.java | 23 ++++- .../jclouds/glesys/features/DomainClient.java | 9 +- .../glesys/features/EmailAsyncClient.java | 2 +- .../jclouds/glesys/features/EmailClient.java | 39 ++++++++- .../jclouds/glesys/features/ServerClient.java | 4 +- .../glesys/options/DomainAddOptions.java | 75 +++++++++++++++++ .../jclouds/glesys/options/DomainOptions.java | 51 ++++++++--- .../options/DomainRecordAddOptions.java | 13 ++- .../options/DomainRecordEditOptions.java | 63 ++++++++++++++ .../options/DomainRecordModifyOptions.java | 83 ------------------ .../glesys/options/EmailCreateOptions.java | 11 ++- .../glesys/options/EmailEditOptions.java | 23 ++++- .../glesys/options/ServerCloneOptions.java | 24 +++--- .../glesys/options/ServerEditOptions.java | 6 ++ .../features/DomainAsyncClientTest.java | 4 +- .../glesys/features/DomainClientLiveTest.java | 51 +++++++++++ .../glesys/features/EmailClientLiveTest.java | 84 ++++++++----------- .../glesys/features/ServerClientLiveTest.java | 17 ++-- 27 files changed, 452 insertions(+), 204 deletions(-) create mode 100644 sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java create mode 100644 sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java delete mode 100644 sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordModifyOptions.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java index 1d87820fb8..cfbb059b87 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java @@ -74,18 +74,22 @@ public class Archive implements Comparable { private final String freeSize; private final boolean locked; + /** @return the name (username) of the archive */ public String getUsername() { return username; } + /** @return the total size of the archive, ex. "10 GB" */ public String getTotalSize() { return totalSize; } + /** @return the free space left of the archive */ public String getFreeSize() { return freeSize; } + /** @return true if the archive is locked */ public boolean isLocked() { return locked; } @@ -97,7 +101,6 @@ public class Archive implements Comparable { this.locked = locked; } - @Override public int hashCode() { return Objects.hashCode(username); diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java index bdee0df871..5aa645dfed 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java @@ -84,18 +84,22 @@ public class Domain implements Comparable { this.glesysNameServer = glesysNameServer; } + /** @return the domain name, ex. "jclouds.org" */ public String getDomain() { return domain; } + /** @return the date the domain was registered with GleSYS */ public Date getCreateTime() { return createTime; } + /** @return the number of DNS records for this domain */ public int getRecordCount() { return recordCount; } + /** @return true if a GleSYS nameserver holds the records */ public boolean getGlesysNameServer() { return glesysNameServer; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java index 86b4fe6487..3ea489648b 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java @@ -95,26 +95,45 @@ public class DomainRecord implements Comparable { this.ttl = ttl; } + /** + * @return the id of the record used to modify it via the API + * @see org.jclouds.glesys.features.DomainClient + */ public String getId() { return id; } + /** + * @return the zone content of the record + */ public String getZone() { return zone; } + /** + * @return the host content of the record + */ public String getHost() { return host; } + /** + * @return the type of the record, ex. "A" + */ public String getType() { return type; } + /** + * @return the data content of the record + */ public String getData() { return data; } + /** + * @return the TTL/Time-to-live for the record + */ public int getTtl() { return ttl; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java index 3846c4e197..af6accd5da 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/Email.java @@ -139,26 +139,32 @@ public class Email implements Comparable { this.modified = modified; } + /** @return the e-mail address for this e-mail account */ public String getAccount() { return account; } + /** @return the quota for this e-mail account */ public String getQuota() { return quota; } + /** @return the amount of quota currently in use */ public String getUsedQuota() { return usedQuota; } + /** @return the antispam level of the e-mail account */ public int getAntispamLevel() { return antispamLevel; } + /** @return true if antivirus is enabled for this e-mail account */ public boolean getAntiVirus() { return antiVirus; } + /** @return true if auto-respond is enabled for this e-mail account */ public boolean getAutoRespond() { return autoRespond; } @@ -167,14 +173,17 @@ public class Email implements Comparable { return autoRespondMessage; } + /** @return true if saving is enabled for auto-respond e-mails */ public boolean getAutoRespondSaveEmail() { return autoRespondSaveEmail; } + /** @return when this account was created */ public Date getCreated() { return created; } + /** @return when this account was last modified */ public Date getModified() { return modified; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java index 708dcc1a62..f37ee3db56 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java @@ -25,6 +25,8 @@ import com.google.common.collect.ImmutableSet; import java.util.Set; /** + * Structure containing all information about e-mail addresses for a GleSYS account + * * @author Adam Lowe * @see */ @@ -68,10 +70,12 @@ public class EmailOverview { this.domains = domains; } + /** @return summary information about the account */ public EmailOverviewSummary getSummary() { return summary; } + /** @return the set of detailed information about the e-mail addresses and aliases for each domain */ public Set getDomains() { return domains == null ? ImmutableSet.of() : domains; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java index 0836645591..6475bf46b4 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java @@ -21,6 +21,8 @@ package org.jclouds.glesys.domain; import com.google.common.base.Objects; /** + * Detailed information about e-mail settings for a single domain + * * @author Adam Lowe * @see */ @@ -68,14 +70,17 @@ public class EmailOverviewDomain { this.aliases = aliases; } + /** @return the domain name */ public String getDomain() { return domain; } + /** @return the number of e-mail accounts in the domain */ public int getAccounts() { return accounts; } + /** @return the number of e-mail aliases in the domain */ public int getAliases() { return aliases; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java index 06bf11419f..d8553bd0d8 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java @@ -22,6 +22,8 @@ import com.google.common.base.Objects; import com.google.gson.annotations.SerializedName; /** + * Summary information of e-mail settings and limits for a GleSYS account + * * @author Adam Lowe * @see */ @@ -79,18 +81,22 @@ public class EmailOverviewSummary { this.maxAliases = maxAliases; } + /** @return the number of e-mail accounts */ public int getAccounts() { return accounts; } + /** @return the maximum number of e-mail accounts */ public int getMaxAccounts() { return maxAccounts; } + /** @return the number of e-mail aliases */ public int getAliases() { return aliases; } + /** @return the maximum number of e-mail aliases */ public int getMaxAliases() { return maxAliases; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java index 07aa87b352..7f02659c96 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerCreated.java @@ -30,8 +30,8 @@ import com.google.common.collect.ImmutableList; import com.google.gson.annotations.SerializedName; /** - * Connection information to connect to a server with VNC. - * + * Information about a new server + * * @author Adam Lowe * @see */ @@ -44,11 +44,12 @@ public class ServerCreated { private String id; private String hostname; private List ips; - + public Builder id(String id) { this.id = id; return this; } + public Builder ips(List ips) { this.ips = ips; return this; @@ -57,16 +58,16 @@ public class ServerCreated { public Builder ips(ServerCreatedIp... ips) { return ips(Arrays.asList(ips)); } - + public Builder hostname(String hostname) { this.hostname = hostname; return this; } - + public ServerCreated build() { return new ServerCreated(id, hostname, ips); } - + public Builder fromServerCreated(ServerCreated in) { return id(in.getId()).hostname(in.getHostname()).ips(in.getIps()); } @@ -85,14 +86,20 @@ public class ServerCreated { this.ips = ips; } + /** + * @return the id of the server (used for other calls to identify the server. + * @see org.jclouds.glesys.features.ServerClient + */ public String getId() { return id; } + /** @return the hostname of the server */ public String getHostname() { return hostname; } + /** @return the IP addresses assigned to the server */ public List getIps() { return ips == null ? ImmutableList.of() : ips; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java index 24ab2a9792..7eefe11bf9 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java @@ -81,6 +81,9 @@ public class ServerUptime { return new ServerUptime(time); } + /** + * @return the number of seconds the server has been up + */ public long getTime() { return time; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java index c0ba9e5e32..d719a24c7f 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncClient.java @@ -21,9 +21,10 @@ package org.jclouds.glesys.features; import com.google.common.util.concurrent.ListenableFuture; import org.jclouds.glesys.domain.Domain; import org.jclouds.glesys.domain.DomainRecord; +import org.jclouds.glesys.options.DomainAddOptions; import org.jclouds.glesys.options.DomainOptions; import org.jclouds.glesys.options.DomainRecordAddOptions; -import org.jclouds.glesys.options.DomainRecordModifyOptions; +import org.jclouds.glesys.options.DomainRecordEditOptions; import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.RequestFilters; @@ -63,7 +64,7 @@ public interface DomainAsyncClient { */ @POST @Path("/domain/add/format/json") - ListenableFuture addDomain(@FormParam("name") String name, DomainOptions... options); + ListenableFuture addDomain(@FormParam("name") String name, DomainAddOptions... options); /** * @see DomainClient#editDomain @@ -72,26 +73,42 @@ public interface DomainAsyncClient { @Path("/domain/edit/format/json") ListenableFuture editDomain(@FormParam("domain") String domain, DomainOptions... options); + + /** + * @see DomainClient#deleteDomain + */ @POST @Path("/domain/delete/format/json") ListenableFuture deleteDomain(@FormParam("domain") String domain); + /** + * @see DomainClient#listRecords + */ @POST @Path("/domain/list_records/format/json") @SelectJson("records") @Consumes(MediaType.APPLICATION_JSON) ListenableFuture> listRecords(@FormParam("domain") String domain); + /** + * @see DomainClient#addRecord + */ @POST @Path("/domain/add_record/format/json") ListenableFuture addRecord(@FormParam("domain") String domain, @FormParam("host") String host, @FormParam("type") String type, @FormParam("data") String data, DomainRecordAddOptions... options); + /** + * @see DomainClient#editRecord + */ @POST @Path("/domain/update_record/format/json") - ListenableFuture editRecord(@FormParam("record_id") String record_id, DomainRecordModifyOptions... options); + ListenableFuture editRecord(@FormParam("record_id") String record_id, DomainRecordEditOptions... options); + /** + * @see DomainClient#deleteRecord + */ @POST @Path("/domain/delete_record/format/json") ListenableFuture deleteRecord(@FormParam("record_id") String recordId); diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java index 80d0b3e90e..f02a776ad7 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/DomainClient.java @@ -21,15 +21,16 @@ package org.jclouds.glesys.features; import org.jclouds.concurrent.Timeout; import org.jclouds.glesys.domain.Domain; import org.jclouds.glesys.domain.DomainRecord; +import org.jclouds.glesys.options.DomainAddOptions; import org.jclouds.glesys.options.DomainOptions; import org.jclouds.glesys.options.DomainRecordAddOptions; -import org.jclouds.glesys.options.DomainRecordModifyOptions; +import org.jclouds.glesys.options.DomainRecordEditOptions; import java.util.Set; import java.util.concurrent.TimeUnit; /** - * Provides synchronous access to Invoice requests. + * Provides synchronous access to Domain requests. *

* * @author Adam Lowe @@ -52,7 +53,7 @@ public interface DomainClient { * @param domain the name of the domain to add. * @param options optional parameters */ - void addDomain(String domain, DomainOptions... options); + void addDomain(String domain, DomainAddOptions... options); /** * Add a domain to the Glesys dns-system @@ -94,7 +95,7 @@ public interface DomainClient { * @param options the settings to change * @see #listRecords to retrieve the necessary ids */ - void editRecord(String recordId, DomainRecordModifyOptions... options); + void editRecord(String recordId, DomainRecordEditOptions... options); /** * Delete a DNS record diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java index 7d88a81c32..cd940087bd 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java @@ -50,7 +50,7 @@ import com.google.common.util.concurrent.ListenableFuture; public interface EmailAsyncClient { /** - * @see org.jclouds.glesys.features.EmailClient#emailOverview + * @see org.jclouds.glesys.features.EmailClient#getEmailOverview */ @POST @Path("/email/overview/format/json") diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java index b2304e4a8a..f224bbcff5 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java @@ -46,19 +46,52 @@ public interface EmailClient { EmailOverview getEmailOverview(); /** - * - * @return + * Get the set of detailed information about e-mail accounts + * + * @return the relevant set of details */ Set listAccounts(String domain); + /** + * Create a new e-mail account + * + * @param accountAddress the e-mail address to use (the domain should already exist) + * @param password the password to use for the mailbox + * @param options optional parameters + * @see DomainClient#addDomain + */ void createAccount(String accountAddress, String password, EmailCreateOptions... options); + /** + * Create an e-mail alias for an e-mail account + * + * @param aliasAddress the address to use for the alias (the domain should already exist) + * @param toEmailAddress the existing e-mail account address the alias should forward to + * @see DomainClient#addDomain + */ void createAlias(String aliasAddress, String toEmailAddress); + /** + * Adjust an e-mail account's settings + * + * @param accountAddress the existing e-mail account address + * @param options optional parameters + */ void editAccount(String accountAddress, EmailEditOptions... options); - + + /** + * Adjust (re-target) an e-mail alias + * + * @param aliasAddress the existing alias e-mail address + * @param toEmailAddress the existing e-mail account address the alias should forward to + */ void editAlias(String aliasAddress, String toEmailAddress); + /** + * Delete an e-mail account or alias + * + * @param accountAddress the existing alias e-mail account or alias address + */ void delete(String accountAddress); } \ No newline at end of file diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java index 8d0b96602a..251d1a32ed 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ServerClient.java @@ -100,9 +100,9 @@ public interface ServerClient { /** * Get information about the OS templates available * - * @return a map of templates, keyed on platform + * @return the set of information about each template */ - Map> getTemplates(); + Set getTemplates(); /** * Get information about valid arguments to #createServer for each platform diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java new file mode 100644 index 0000000000..cba2b0b0c3 --- /dev/null +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java @@ -0,0 +1,75 @@ +package org.jclouds.glesys.options; + +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * @author Adam Lowe + */ +public class DomainAddOptions extends DomainOptions { + public static class Builder { + /** + * @see DomainAddOptions#primaryNameServer + */ + public static DomainAddOptions primaryNameServer(String primaryNameServer) { + return DomainAddOptions.class.cast(new DomainAddOptions().primaryNameServer(primaryNameServer)); + } + + /** + * @see DomainAddOptions#responsiblePerson + */ + public static DomainAddOptions responsiblePerson(String responsiblePerson) { + return DomainAddOptions.class.cast(new DomainAddOptions().responsiblePerson(responsiblePerson)); + } + + /** + * @see DomainAddOptions#ttl + */ + public static DomainAddOptions ttl(int ttl) { + return DomainAddOptions.class.cast(new DomainAddOptions().ttl(ttl)); + } + + /** + * @see DomainAddOptions#refresh + */ + public static DomainAddOptions refresh(int refresh) { + return DomainAddOptions.class.cast(new DomainAddOptions().refresh(refresh)); + } + + /** + * @see DomainAddOptions#retry + */ + public static DomainAddOptions retry(int retry) { + return DomainAddOptions.class.cast(new DomainAddOptions().retry(retry)); + } + + /** + * @see DomainAddOptions#expire + */ + public static DomainAddOptions expire(int expire) { + return DomainAddOptions.class.cast(new DomainAddOptions().expire(expire)); + } + + /** + * @see DomainAddOptions#minimum + */ + public static DomainAddOptions minimum(int minimum) { + return DomainAddOptions.class.cast(new DomainAddOptions().minimum(minimum)); + } + + /** + * @see DomainAddOptions#minimalRecords + */ + public static DomainAddOptions minimalRecords() { + return DomainAddOptions.class.cast(new DomainAddOptions().minimalRecords()); + } + } + + /** + * Ensure only NS and SOA records will be created by default, when this option is not used a number of default records will be created on the domain. + */ + public DomainOptions minimalRecords() { + formParameters.put("create_records", "0"); + return this; + } + +} \ No newline at end of file diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java index 6bc47aa8bf..0a322890f5 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java @@ -52,7 +52,7 @@ public class DomainOptions extends BaseHttpRequestOptions { /** * @see DomainOptions#refresh */ - public static DomainOptions refresh(String refresh) { + public static DomainOptions refresh(int refresh) { DomainOptions options = new DomainOptions(); return options.refresh(refresh); } @@ -60,7 +60,7 @@ public class DomainOptions extends BaseHttpRequestOptions { /** * @see DomainOptions#retry */ - public static DomainOptions retry(String retry) { + public static DomainOptions retry(int retry) { DomainOptions options = new DomainOptions(); return options.retry(retry); } @@ -68,7 +68,7 @@ public class DomainOptions extends BaseHttpRequestOptions { /** * @see DomainOptions#expire */ - public static DomainOptions expire(String expire) { + public static DomainOptions expire(int expire) { DomainOptions options = new DomainOptions(); return options.expire(expire); } @@ -76,44 +76,71 @@ public class DomainOptions extends BaseHttpRequestOptions { /** * @see DomainOptions#minimum */ - public static DomainOptions minimum(String minimum) { + public static DomainOptions minimum(int minimum) { DomainOptions options = new DomainOptions(); return options.minimum(minimum); } } + /** + * Configure the primary DNS server for this domain. + */ public DomainOptions primaryNameServer(String primaryNameServer) { formParameters.put("primary_ns", primaryNameServer); return this; } + /** + * Configure the E-mail address of the person responsible for this domain (usually attached to MX records). + */ public DomainOptions responsiblePerson(String responsiblePerson) { + responsiblePerson = responsiblePerson.replaceAll("@", "."); + if (!responsiblePerson.endsWith(".")) { + responsiblePerson = responsiblePerson + "."; + } formParameters.put("resp_person", responsiblePerson); return this; } + /** + * TTL (time to live). The number of seconds a domain name is cached locally before expiration and return to authoritative nameservers for updates + */ public DomainOptions ttl(int ttl) { formParameters.put("ttl", Integer.toString(ttl)); return this; } - public DomainOptions refresh(String refresh) { - formParameters.put("refresh", refresh); + /** + * Configure the number of seconds between update requests from secondary and slave name servers + */ + public DomainOptions refresh(int refresh) { + formParameters.put("refresh", Integer.toString(refresh)); return this; } - public DomainOptions retry(String retry) { - formParameters.put("retry", retry); + /** + * Configure the number of seconds the secondary/slave will wait before retrying when the last attempt failed + */ + public DomainOptions retry(int retry) { + formParameters.put("retry", Integer.toString(retry)); return this; } - public DomainOptions expire(String expire) { - formParameters.put("primary_ns", expire); + /** + * Configure the number of seconds a master or slave will wait before considering the data stale if it cannot reach the primary name server + */ + public DomainOptions expire(int expire) { + formParameters.put("primary_ns", Integer.toString(expire)); return this; } - public DomainOptions minimum(String minimum) { - formParameters.put("minimum", minimum); + /** + * Configure the minimum/default TTL if the domain does not specify ttl + * + * @see #ttl + */ + public DomainOptions minimum(int minimum) { + formParameters.put("minimum", Integer.toString(minimum)); return this; } } \ No newline at end of file diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java index fc304b841e..281cfbdf48 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordAddOptions.java @@ -37,24 +37,21 @@ public class DomainRecordAddOptions extends BaseHttpRequestOptions { /** * @see DomainRecordAddOptions#mxPriority */ - public static DomainRecordAddOptions mxPriority(String mxPriority) { + public static DomainRecordAddOptions mxPriority(int mxPriority) { DomainRecordAddOptions options = new DomainRecordAddOptions(); return options.mxPriority(mxPriority); } } - public DomainRecordAddOptions host(String host) { - formParameters.put("host", host); - return this; - } - + /** Configure TTL/Time-to-live for record */ public DomainRecordAddOptions ttl(int ttl) { formParameters.put("ttl", Integer.toString(ttl)); return this; } - public DomainRecordAddOptions mxPriority(String mxPriority) { - formParameters.put("mx_priority", mxPriority); + /** Configure the priority of an MX record */ + public DomainRecordAddOptions mxPriority(int mxPriority) { + formParameters.put("mx_priority", Integer.toString(mxPriority)); return this; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java new file mode 100644 index 0000000000..f375375320 --- /dev/null +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java @@ -0,0 +1,63 @@ +package org.jclouds.glesys.options; + +/** + * @author Adam Lowe + */ +public class DomainRecordEditOptions extends DomainRecordAddOptions { + + public static class Builder { + /** + * @see DomainRecordEditOptions#host + */ + public static DomainRecordEditOptions host(String host) { + return new DomainRecordEditOptions().host(host); + } + + /** + * @see DomainRecordEditOptions#type + */ + public static DomainRecordEditOptions type(String type) { + return new DomainRecordEditOptions().type(type); + } + + /** + * @see DomainRecordEditOptions#data + */ + public static DomainRecordEditOptions data(String data) { + return new DomainRecordEditOptions().data(data); + } + + /** + * @see DomainRecordEditOptions#ttl + */ + public static DomainRecordEditOptions ttl(int ttl) { + return DomainRecordEditOptions.class.cast(new DomainRecordEditOptions().ttl(ttl)); + } + + /** + * @see DomainRecordEditOptions#mxPriority + */ + public static DomainRecordEditOptions mxPriority(int mxPriority) { + return DomainRecordEditOptions.class.cast(new DomainRecordEditOptions().mxPriority(mxPriority)); + } + } + + + /** Configure the hostname attached to this record */ + public DomainRecordEditOptions host(String host) { + formParameters.put("host", host); + return this; + } + + /** Configure the type of record, ex. "A", "CNAME" or "MX" */ + public DomainRecordEditOptions type(String type) { + formParameters.put("type", type); + return this; + } + + /** Set the content of this record (depending on type, for an "A" record this would be an ip address) */ + public DomainRecordEditOptions data(String data) { + formParameters.put("data", data); + return this; + } +} \ No newline at end of file diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordModifyOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordModifyOptions.java deleted file mode 100644 index 50e46d9de9..0000000000 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordModifyOptions.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * 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.glesys.options; - -/** - * @author Adam Lowe - */ -public class DomainRecordModifyOptions extends DomainRecordAddOptions { - - public static class Builder { - /** - * @see org.jclouds.glesys.options.DomainRecordAddOptions#host - */ - public static DomainRecordModifyOptions host(String host) { - DomainRecordModifyOptions options = new DomainRecordModifyOptions(); - return options.host(host); - } - - /** - * @see org.jclouds.glesys.options.DomainRecordModifyOptions#type - */ - public static DomainRecordModifyOptions type(String type) { - DomainRecordModifyOptions options = new DomainRecordModifyOptions(); - return options.type(type); - } - - /** - * @see org.jclouds.glesys.options.DomainRecordModifyOptions#data - */ - public static DomainRecordModifyOptions data(String data) { - DomainRecordModifyOptions options = new DomainRecordModifyOptions(); - return options.data(data); - } - - /** - * @see org.jclouds.glesys.options.DomainRecordModifyOptions#ttl - */ - public static DomainRecordModifyOptions ttl(int ttl) { - DomainRecordModifyOptions options = new DomainRecordModifyOptions(); - return DomainRecordModifyOptions.class.cast(options.ttl(ttl)); - } - - /** - * @see org.jclouds.glesys.options.DomainRecordModifyOptions#mxPriority - */ - public static DomainRecordModifyOptions mxPriority(String mxPriority) { - DomainRecordModifyOptions options = new DomainRecordModifyOptions(); - return DomainRecordModifyOptions.class.cast(options.mxPriority(mxPriority)); - } - } - - public DomainRecordModifyOptions host(String host) { - formParameters.put("host", host); - return this; - } - - - public DomainRecordModifyOptions type(String type) { - formParameters.put("type", type); - return this; - } - - public DomainRecordModifyOptions data(String data) { - formParameters.put("data", data); - return this; - } -} \ No newline at end of file diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java index b253f6ca76..a3c74ca975 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailCreateOptions.java @@ -57,33 +57,38 @@ public class EmailCreateOptions extends BaseHttpRequestOptions { /** * @see EmailCreateOptions#autorespondMessage */ - public static EmailCreateOptions autorespondMessage(boolean autorespondMessage) { + public static EmailCreateOptions autorespondMessage(String autorespondMessage) { return new EmailCreateOptions().autorespondMessage(autorespondMessage); } } + /** Configure the antispam level of the account */ public EmailCreateOptions antispamLevel(int antispamLevel) { formParameters.put("antispamlevel", Integer.toString(antispamLevel)); return this; } + /** Enable or disable virus checking */ public EmailCreateOptions antiVirus(boolean antiVirus) { formParameters.put("antivirus", Integer.toString(antiVirus ? 1 : 0)); return this; } + /** Enable or disable auto-respond */ public EmailCreateOptions autorespond(boolean autorespond) { formParameters.put("autorespond", Integer.toString(autorespond ? 1 : 0)); return this; } + /** Enable or disable saving of auto-respond e-mails */ public EmailCreateOptions autorespondSaveEmail(boolean autorespondSaveEmail) { formParameters.put("autorespondsaveemail", Integer.toString(autorespondSaveEmail ? 1 : 0)); return this; } - public EmailCreateOptions autorespondMessage(boolean autorespondMessage) { - formParameters.put("autorespondmessage", Integer.toString(autorespondMessage ? 1 : 0)); + /** Configure the auto-respond message */ + public EmailCreateOptions autorespondMessage(String autorespondMessage) { + formParameters.put("autorespondmessage", autorespondMessage); return this; } } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java index 97f0e90c5d..7e07600067 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/EmailEditOptions.java @@ -26,31 +26,50 @@ package org.jclouds.glesys.options; public class EmailEditOptions extends EmailCreateOptions { public static class Builder { + /** + * @see org.jclouds.glesys.options.EmailEditOptions#antispamLevel + */ public static EmailEditOptions antispamLevel(int antispamLevel) { return EmailEditOptions.class.cast(new EmailEditOptions().antispamLevel(antispamLevel)); } + /** + * @see org.jclouds.glesys.options.EmailEditOptions#antiVirus + */ public static EmailEditOptions antiVirus(boolean antiVirus) { return EmailEditOptions.class.cast(new EmailEditOptions().antiVirus(antiVirus)); } + /** + * @see org.jclouds.glesys.options.EmailEditOptions#autorespond + */ public static EmailEditOptions autorespond(boolean autorespond) { return EmailEditOptions.class.cast(new EmailEditOptions().autorespond(autorespond)); } + /** + * @see org.jclouds.glesys.options.EmailEditOptions#autorespondSaveEmail + */ public static EmailEditOptions autorespondSaveEmail(boolean autorespondSaveEmail) { return EmailEditOptions.class.cast(new EmailEditOptions().autorespondSaveEmail(autorespondSaveEmail)); } - public static EmailEditOptions autorespondMessage(boolean autorespondMessage) { + /** + * @see org.jclouds.glesys.options.EmailEditOptions#autorespondMessage + */ + public static EmailEditOptions autorespondMessage(String autorespondMessage) { return EmailEditOptions.class.cast(new EmailEditOptions().autorespondMessage(autorespondMessage)); } - public static EmailEditOptions autorespondMessage(String password) { + /** + * @see org.jclouds.glesys.options.EmailEditOptions#password + */ + public static EmailEditOptions password(String password) { return new EmailEditOptions().password(password); } } + /** Reset the password for this account */ public EmailEditOptions password(String password) { formParameters.put("password", password); return this; diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java index 388a49d632..6ae8aaf54d 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java @@ -27,59 +27,55 @@ public class ServerCloneOptions extends ServerEditOptions { * @see org.jclouds.glesys.options.ServerCloneOptions#disksize */ public static ServerCloneOptions disksize(int disksize) { - ServerCloneOptions options = new ServerCloneOptions(); - return ServerCloneOptions.class.cast(options.disksize(disksize)); + return ServerCloneOptions.class.cast(new ServerCloneOptions().disksize(disksize)); } /** * @see org.jclouds.glesys.options.ServerCloneOptions#memorysize */ public static ServerCloneOptions memorysize(int memorysize) { - ServerCloneOptions options = new ServerCloneOptions(); - return ServerCloneOptions.class.cast(options.memorysize(memorysize)); + return ServerCloneOptions.class.cast(new ServerCloneOptions().memorysize(memorysize)); } /** * @see org.jclouds.glesys.options.ServerCloneOptions#cpucores */ public static ServerCloneOptions cpucores(int cpucores) { - ServerCloneOptions options = new ServerCloneOptions(); - return ServerCloneOptions.class.cast(options.cpucores(cpucores)); + return ServerCloneOptions.class.cast(new ServerCloneOptions().cpucores(cpucores)); } /** * @see org.jclouds.glesys.options.ServerCloneOptions#cpucores */ public static ServerCloneOptions transfer(int transfer) { - ServerCloneOptions options = new ServerCloneOptions(); - return ServerCloneOptions.class.cast(options.transfer(transfer)); + return ServerCloneOptions.class.cast(new ServerCloneOptions().transfer(transfer)); } /** * @see org.jclouds.glesys.options.ServerCloneOptions#hostname */ public static ServerCloneOptions hostname(String hostname) { - ServerCloneOptions options = new ServerCloneOptions(); - return ServerCloneOptions.class.cast(options.hostname(hostname)); + return ServerCloneOptions.class.cast(new ServerCloneOptions().hostname(hostname)); } /** * @see org.jclouds.glesys.options.ServerEditOptions#description */ public static ServerCloneOptions description(String description) { - ServerCloneOptions options = new ServerCloneOptions(); - return ServerCloneOptions.class.cast(options.description(description)); + return ServerCloneOptions.class.cast(new ServerCloneOptions().description(description)); } /** * @see org.jclouds.glesys.options.ServerCloneOptions#dataCenter */ public static ServerCloneOptions dataCenter(String dataCenter) { - ServerCloneOptions options = new ServerCloneOptions(); - return options.dataCenter(dataCenter); + return new ServerCloneOptions().dataCenter(dataCenter); } } + /** + * Configure which datacenter to create the clone in + */ public ServerCloneOptions dataCenter(String dataCenter) { formParameters.put("datacenter", dataCenter); return this; diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java index b45070b9d7..ba8a0ffe36 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerEditOptions.java @@ -76,31 +76,37 @@ public class ServerEditOptions extends BaseHttpRequestOptions { } } + /** Configure the size of the disk, in GB, of the server */ public ServerEditOptions disksize(int disksize) { formParameters.put("disksize", Integer.toString(disksize)); return this; } + /** Configure the amount of RAM, in MB, allocated to the server */ public ServerEditOptions memorysize(int memorysize) { formParameters.put("memorysize", Integer.toString(memorysize)); return this; } + /** Configure the number of CPU cores allocated to the server */ public ServerEditOptions cpucores(int cpucores) { formParameters.put("cpucores", Integer.toString(cpucores)); return this; } + /** Configure the transfer setting for the server */ public ServerEditOptions transfer(int transfer) { formParameters.put("cpucores", Integer.toString(transfer)); return this; } + /** Configure the host name of the server (must be unique within the GleSYS account) */ public ServerEditOptions hostname(String hostname) { formParameters.put("hostname", hostname); return this; } + /** Configure the description of the server */ public ServerEditOptions description(String description) { formParameters.put("description", description); return this; diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java index e945854a6c..78dcafa6bc 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java @@ -48,8 +48,8 @@ public class DomainAsyncClientTest extends BaseGleSYSAsyncClientTest domainCounter; private RetryablePredicate recordCounter; + @Test + public void testEditDomain() throws Exception { + client.editDomain(testDomain, DomainOptions.Builder.responsiblePerson("tester.jclouds.org")); + assertTrue(client.listDomains().contains(Domain.builder().domain(testDomain).build())); + } + @Test public void testCreateRecord() throws Exception { int before = client.listRecords(testDomain).size(); @@ -86,6 +97,46 @@ public class DomainClientLiveTest extends BaseGleSYSClientLiveTest { client.addRecord(testDomain, "test", "A", "127.0.0.1"); assertTrue(recordCounter.apply(before + 1)); + + for(DomainRecord record : client.listRecords(testDomain)) { + if ("test".equals(record.getHost())) { + assertEquals(record.getType(), "A"); + assertEquals(record.getData(), "127.0.0.1"); + } + } + } + + @Test + public void testEditRecord() throws Exception { + int before = client.listRecords(testDomain).size(); + + client.addRecord(testDomain, "testeditbefore", "A", "127.0.0.1"); + + assertTrue(recordCounter.apply(before + 1)); + + String recordId = null; + for(DomainRecord record : client.listRecords(testDomain)) { + if ("testeditbefore".equals(record.getHost())) { + assertEquals(record.getType(), "A"); + assertEquals(record.getData(), "127.0.0.1"); + recordId = record.getId(); + } + } + + assertNotNull(recordId); + + client.editRecord(recordId, DomainRecordEditOptions.Builder.host("testeditafter")); + + boolean found = false; + for(DomainRecord record : client.listRecords(testDomain)) { + if (recordId.equals(record.getId())) { + assertEquals(record.getHost(), "testeditafter"); + assertEquals(record.getType(), "A"); + assertEquals(record.getData(), "127.0.0.1"); + found = true; + } + } + assertTrue(found); } @Test diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java index 845d17396e..108c608b1c 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientLiveTest.java @@ -16,24 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -/** -* 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.glesys.features; import com.google.common.base.Predicate; @@ -52,10 +34,10 @@ import java.util.concurrent.TimeUnit; import static org.testng.Assert.*; /** -* Tests behavior of {@code EmailClient} -* -* @author Adam Lowe -*/ + * Tests behavior of {@code EmailClient} + * + * @author Adam Lowe + */ @Test(groups = "live", testName = "EmailClientLiveTest", singleThreaded = true) public class EmailClientLiveTest extends BaseGleSYSClientLiveTest { @@ -64,15 +46,8 @@ public class EmailClientLiveTest extends BaseGleSYSClientLiveTest { super.setupClient(); client = context.getApi().getEmailClient(); - try { - client.delete("test@" + testDomain); - client.delete("test2@" + testDomain); - context.getApi().getDomainClient().deleteDomain(testDomain); - } catch(Exception e) { - } - serverId = createServer("test-email-jclouds").getServerId(); - + createDomain(testDomain); emailAccountCounter = new RetryablePredicate( @@ -80,42 +55,55 @@ public class EmailClientLiveTest extends BaseGleSYSClientLiveTest { public boolean apply(Integer value) { return client.listAccounts(testDomain).size() == value; } - }, 30, 1, TimeUnit.SECONDS); - + }, 90, 5, TimeUnit.SECONDS); + + assertTrue(emailAccountCounter.apply(0)); } - @AfterGroups(groups = {"live"}) public void tearDown() { client.delete("test@" + testDomain); + client.delete("test1@" + testDomain); assertTrue(emailAccountCounter.apply(0)); context.getApi().getDomainClient().deleteDomain(testDomain); context.getApi().getServerClient().destroyServer(serverId, ServerDestroyOptions.Builder.discardIp()); super.tearDown(); } - + private EmailClient client; private String serverId; private final String testDomain = "email-test.jclouds.org"; private RetryablePredicate emailAccountCounter; - + @Test - public void createEmail() { - client.createAccount("test@" + testDomain, "password", EmailCreateOptions.Builder.antiVirus(true)); + public void testCreateEmail() { + client.createAccount("test@" + testDomain, "password", + EmailCreateOptions.Builder.antiVirus(true).autorespond(true).autorespondMessage("out of office")); + assertTrue(emailAccountCounter.apply(1)); + + client.createAccount("test1@" + testDomain, "password"); + + assertTrue(emailAccountCounter.apply(2)); } - @Test(dependsOnMethods = "createEmail") - public void createAlias() { + @Test(dependsOnMethods = "testCreateEmail") + public void testAliases() { client.createAlias("test2@" + testDomain, "test@" + testDomain); EmailOverview overview = client.getEmailOverview(); assertTrue(overview.getSummary().getAliases() == 1); + + // TODO verify the result of editing the alias + client.editAlias("test2@" + testDomain, "test1@" + testDomain); + overview = client.getEmailOverview(); + assertTrue(overview.getSummary().getAliases() == 1); + client.delete("test2@" + testDomain); overview = client.getEmailOverview(); assertTrue(overview.getSummary().getAliases() == 0); } - - @Test(dependsOnMethods = "createEmail") + + @Test(dependsOnMethods = "testCreateEmail") public void testOverview() throws Exception { EmailOverview overview = client.getEmailOverview(); assertNotNull(overview.getSummary()); @@ -125,30 +113,30 @@ public class EmailClientLiveTest extends BaseGleSYSClientLiveTest { assertTrue(overview.getSummary().getMaxAliases() > 0); assertNotNull(overview.getDomains()); assertFalse(overview.getDomains().isEmpty()); - + EmailOverviewDomain domain = EmailOverviewDomain.builder().domain(testDomain).accounts(1).build(); assertTrue(overview.getDomains().contains(domain)); } - @Test(dependsOnMethods = "createEmail") + @Test(dependsOnMethods = "testCreateEmail") public void testListAccounts() throws Exception { Set accounts = client.listAccounts(testDomain); assertTrue(accounts.size() >= 1); } - @Test(dependsOnMethods = "createEmail") + @Test(dependsOnMethods = "testCreateEmail") public void testEditAccount() throws Exception { Set accounts = client.listAccounts(testDomain); - for(Email account : accounts) { + for (Email account : accounts) { if (account.getAccount().equals("test@" + testDomain)) { assertTrue(account.getAntiVirus()); } } - + client.editAccount("test@" + testDomain, EmailEditOptions.Builder.antiVirus(false)); - + accounts = client.listAccounts(testDomain); - for(Email account : accounts) { + for (Email account : accounts) { if (account.getAccount().equals("test@" + testDomain)) { assertFalse(account.getAntiVirus()); } diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java index ee0230ebdf..6f28007fdf 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientLiveTest.java @@ -98,26 +98,19 @@ public class ServerClientLiveTest extends BaseGleSYSClientLiveTest { @Test public void testListTemplates() throws Exception { - Map> templates = client.getTemplates(); + Set templates = client.getTemplates(); - assertTrue(templates.containsKey("OpenVZ")); - assertTrue(templates.containsKey("Xen")); - - for(ServerTemplate template : templates.get("OpenVZ")) { - checkTemplate(template, "OpenVZ"); - } - - for(ServerTemplate template : templates.get("Xen")) { - checkTemplate(template, "Xen"); + for(ServerTemplate template : templates) { + checkTemplate(template); } } - private void checkTemplate(ServerTemplate t, String platform) { + private void checkTemplate(ServerTemplate t) { assertNotNull(t); assertNotNull(t.getName()); assertNotNull(t.getOs()); - assertEquals(t.getPlatform(), platform); + assertNotNull(t.getPlatform()); assert t.getMinDiskSize() > 0 : t; assert t.getMinMemSize() > 0 : t; } From bb47f6bba10671eb8c91f0045a19fe1765df2b36 Mon Sep 17 00:00:00 2001 From: Adam Lowe Date: Tue, 10 Jan 2012 10:54:03 +0000 Subject: [PATCH 02/82] Switching from AsyncClientTests to ClientExpectTests for Archive, Domain, Email and Server clients --- .../glesys/compute/GleSYSComputeService.java | 11 ++ .../GleSYSComputeServiceContextModule.java | 11 ++ .../jclouds/glesys/domain/ServerDetails.java | 2 +- .../glesys/features/ArchiveAsyncClient.java | 2 +- .../glesys/features/EmailAsyncClient.java | 3 +- .../jclouds/glesys/features/EmailClient.java | 2 +- .../glesys/options/ServerCloneOptions.java | 7 - .../features/ArchiveAsyncClientTest.java | 81 --------- .../features/ArchiveClientExpectTest.java | 107 ++++++++++++ .../features/BaseGleSYSAsyncClientTest.java | 81 --------- .../features/BaseGleSYSClientExpectTest.java | 115 +++++++++++++ .../features/DomainAsyncClientTest.java | 69 -------- .../features/DomainClientExpectTest.java | 84 ++++++++++ .../glesys/features/EmailAsyncClientTest.java | 68 -------- .../features/EmailClientExpectTest.java | 116 +++++++++++++ .../features/ServerAsyncClientTest.java | 136 --------------- .../features/ServerClientExpectTest.java | 158 ++++++++++++++++++ .../ParseServerAllowedArgumentsTest.java | 55 +++--- .../glesys/parse/ParseServerDetailsTest.java | 65 +++++++ .../src/test/resources/server_details.json | 1 + .../src/test/resources/server_limits.json | 1 + 21 files changed, 703 insertions(+), 472 deletions(-) create mode 100644 sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java create mode 100644 sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java delete mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveAsyncClientTest.java create mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java create mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java delete mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java create mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java delete mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAsyncClientTest.java create mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java delete mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerAsyncClientTest.java create mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java create mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java create mode 100644 sandbox-providers/glesys/src/test/resources/server_details.json create mode 100644 sandbox-providers/glesys/src/test/resources/server_limits.json diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java new file mode 100644 index 0000000000..48266e0679 --- /dev/null +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java @@ -0,0 +1,11 @@ +package org.jclouds.glesys.compute; + +/** + * Created by IntelliJ IDEA. + * User: aplowe + * Date: 09/01/2012 + * Time: 13:03 + * To change this template use File | Settings | File Templates. + */ +public class GleSYSComputeService { +} diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java new file mode 100644 index 0000000000..94b33686bd --- /dev/null +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java @@ -0,0 +1,11 @@ +package org.jclouds.glesys.compute.config; + +/** + * Created by IntelliJ IDEA. + * User: aplowe + * Date: 09/01/2012 + * Time: 13:05 + * To change this template use File | Settings | File Templates. + */ +public class GleSYSComputeServiceContextModule { +} diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java index e8347bf444..4622233ac1 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java @@ -111,7 +111,7 @@ public class ServerDetails extends Server { public ServerDetails(String id, String hostname, String datacenter, String platform, String description, int cpuCores, int memory, int disk, Cost cost) { super(id, hostname, datacenter, platform); - this.description = checkNotNull(description, "description"); + this.description = description; this.cpuCores = cpuCores; this.memory = memory; this.disk = disk; diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java index 4098ebeade..f79a77f383 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncClient.java @@ -99,7 +99,7 @@ public interface ArchiveAsyncClient { @Path("/archive/allowedarguments/format/json") @SelectJson("argumentslist") @Consumes(MediaType.APPLICATION_JSON) - @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture getArchiveAllowedArguments(); } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java index cd940087bd..ed303905bf 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncClient.java @@ -37,6 +37,7 @@ import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import com.google.common.util.concurrent.ListenableFuture; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; /** * Provides asynchronous access to E-Mail data via the Glesys REST API. @@ -56,7 +57,7 @@ public interface EmailAsyncClient { @Path("/email/overview/format/json") @SelectJson("response") @Consumes(MediaType.APPLICATION_JSON) - @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture getEmailOverview(); /** diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java index f224bbcff5..f7d75b3b32 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/features/EmailClient.java @@ -32,7 +32,7 @@ import org.jclouds.glesys.options.EmailEditOptions; *

* * @author Adam Lowe - * @see org.jclouds.glesys.features.DomainAsyncClient + * @see org.jclouds.glesys.features.EmailAsyncClient * @see */ @Timeout(duration = 30, timeUnit = TimeUnit.SECONDS) diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java index 6ae8aaf54d..99997e0f91 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/ServerCloneOptions.java @@ -51,13 +51,6 @@ public class ServerCloneOptions extends ServerEditOptions { return ServerCloneOptions.class.cast(new ServerCloneOptions().transfer(transfer)); } - /** - * @see org.jclouds.glesys.options.ServerCloneOptions#hostname - */ - public static ServerCloneOptions hostname(String hostname) { - return ServerCloneOptions.class.cast(new ServerCloneOptions().hostname(hostname)); - } - /** * @see org.jclouds.glesys.options.ServerEditOptions#description */ diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveAsyncClientTest.java deleted file mode 100644 index 124f4ec4f2..0000000000 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveAsyncClientTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * 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.glesys.features; - -import java.util.Map; - -import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions; -import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; -import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; -import org.jclouds.rest.internal.RestAnnotationProcessor; -import org.testng.annotations.Test; - -import com.google.inject.TypeLiteral; - -/** - * Tests annotation parsing of {@code ArchiveAsyncClient} - * - * @author Adam Lowe - */ -@Test(groups = "unit", testName = "ArchiveAsyncClientTest") -public class ArchiveAsyncClientTest extends BaseGleSYSAsyncClientTest { - public ArchiveAsyncClientTest() { - asyncClientClass = ArchiveAsyncClient.class; - remoteServicePrefix = "archive"; - } - - private Map.Entry userName = newEntry("username", "x"); - - public void testListArchives() throws Exception { - testMethod("listArchives", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class); - } - - public void testArchiveDetails() throws Exception { - testMethod("getArchiveDetails", "details", "POST", true, ReturnNullOnNotFoundOr404.class, userName); - } - - public void testCreateArchive() throws Exception { - testMethod("createArchive", "create", "POST", false, MapHttp4xxCodesToExceptions.class, userName, - newEntry("password", "somepass"), newEntry("size", 5)); - } - - public void testDeleteArchive() throws Exception { - testMethod("deleteArchive", "delete", "POST", false, MapHttp4xxCodesToExceptions.class, userName); - } - - public void testResizeArchive() throws Exception { - testMethod("resizeArchive", "resize", "POST", false, MapHttp4xxCodesToExceptions.class, userName, - newEntry("size", "5 GB")); - } - - public void testChangeArchivePassword() throws Exception { - testMethod("changeArchivePassword", "changepassword", "POST", false, MapHttp4xxCodesToExceptions.class, userName, - newEntry("password", "newpass")); - } - - public void testGetArchiveAllowedArguments() throws Exception { - testMethod("getArchiveAllowedArguments", "allowedarguments", "GET", true, ReturnEmptySetOnNotFoundOr404.class); - } - - @Override - protected TypeLiteral> createTypeLiteral() { - return new TypeLiteral>() { - }; - } -} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java new file mode 100644 index 0000000000..524c8b7470 --- /dev/null +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java @@ -0,0 +1,107 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.glesys.features; + +import com.google.common.collect.ImmutableList; +import org.jclouds.glesys.GleSYSClient; +import org.jclouds.glesys.domain.Archive; +import org.jclouds.glesys.domain.ArchiveAllowedArguments; +import org.jclouds.glesys.domain.ArchiveDetails; +import org.jclouds.rest.ResourceNotFoundException; +import org.testng.annotations.Test; + +import java.util.Map; + +import static org.testng.Assert.*; + +/** + * Tests annotation parsing of {@code ArchiveAsyncClient} + * + * @author Adam Lowe + */ +@Test(groups = "unit", testName = "ArchiveAsyncClientTest") +public class ArchiveClientExpectTest extends BaseGleSYSClientExpectTest { + public ArchiveClientExpectTest() { + remoteServicePrefix = "archive"; + } + + private Map.Entry userName = entry("username", "xxxxxx_test1"); + + public void testListArchives() throws Exception { + ArchiveClient client = createMock("list", "POST", 200, "/archive_list.json"); + assertEquals(client.listArchives(), + ImmutableList.of(Archive.builder().username("xxxxx_test1").freeSize("20 GB").totalSize("20 GB").locked(false).build())); + + // check not found response + client = createMock("list", "POST", 404, "Something not found"); + assertTrue(client.listArchives().isEmpty()); + } + + public void testArchiveDetails() throws Exception { + assertEquals(createMock("details", "POST", 200, "/archive_details.json", userName).getArchiveDetails("xxxxxx_test1"), + ArchiveDetails.builder().username("xxxxxx_test1").freeSize("30 GB").totalSize("30 GB").locked(false).build()); + assertNull(createMock("details", "POST", 404, "/archive_details.json", userName).getArchiveDetails("xxxxxx_test1")); + } + + public void testCreateArchive() throws Exception { + createMock("create", "POST", 200, null, userName, entry("size", 5), + entry("password", "somepass")).createArchive(userName.getValue(), "somepass", 5); + } + + public void testDeleteArchive() throws Exception { + createMock("delete", "POST", 200, null, userName).deleteArchive(userName.getValue()); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testDeleteArchiveNotFound() throws Exception { + createMock("delete", "POST", 404, null, userName).deleteArchive(userName.getValue()); + } + + public void testResizeArchive() throws Exception { + createMock("resize", "POST", 200, null, entry("username", "username"), + entry("size", "5")).resizeArchive("username", 5); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testResizeArchiveNotFound() throws Exception { + createMock("resize", "POST", 404, null, entry("username", "username"), entry("size", "5")).resizeArchive("username", 5); + } + + public void testChangeArchivePassword() throws Exception { + createMock("changepassword", "POST", 200, null, userName, + entry("password", "newpass")).changeArchivePassword(userName.getValue(), "newpass"); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testChangeArchivePasswordNotFound() throws Exception { + createMock("changepassword", "POST", 404, null, userName, + entry("password", "newpass")).changeArchivePassword(userName.getValue(), "newpass"); + } + + public void testGetArchiveAllowedArguments() throws Exception { + assertEquals(createMock("allowedarguments", "GET", 200, "/archive_allowed_arguments.json").getArchiveAllowedArguments(), + ArchiveAllowedArguments.builder().archiveSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000).build()); + assertNull(createMock("allowedarguments", "GET", 404, "/archive_allowed_arguments.json").getArchiveAllowedArguments()); + } + + @Override + protected ArchiveClient getClient(GleSYSClient gleSYSClient) { + return gleSYSClient.getArchiveClient(); + } +} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java index 26e799aac4..43d645325a 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java @@ -48,8 +48,6 @@ import com.google.common.collect.Maps; * @author Adam Lowe */ public abstract class BaseGleSYSAsyncClientTest extends RestClientTest { - protected Class asyncClientClass; - protected String remoteServicePrefix; @Override protected void checkFilters(HttpRequest request) { @@ -62,83 +60,4 @@ public abstract class BaseGleSYSAsyncClientTest extends RestClientTest { Properties props = new Properties(); return new RestContextFactory().createContextSpec("glesys", "username", "apiKey", props); } - - @Deprecated - protected Map.Entry newEntry(String key, Object value) { - return Maps.immutableEntry(key, value.toString()); - } - - /** - * Test that a method call is annotated correctly. - *

- * @param localMethod the method to call in asyncClientClass - * @param remoteCall the name of the expected call on the remote server - * @param httpMethod "GET" or "POST" - * @param expectResponse if true check Accept header and response parsers - * @param exceptionParser the class of exception handler expected - * @param args either Map.Entry or BaseHttpRequestOptions that make up the arguments to the method - */ - //TODO: kill this and related logic and transition to BaseRestClientExpectTest - @Deprecated - protected void testMethod(String localMethod, String remoteCall, String httpMethod, boolean expectResponse, - Class exceptionParser, Object... args) throws Exception { - testMethod(localMethod, remoteCall, httpMethod, expectResponse, ParseFirstJsonValueNamed.class, exceptionParser, - args); - } - - @Deprecated - @SuppressWarnings("unchecked") - protected void testMethod(String localMethod, String remoteCall, String httpMethod, boolean expectResponse, Class responseParser, Class exceptionParser, Object... args) throws Exception { - List argStrings = new ArrayList(); - List argValues = new ArrayList(); - - for (Object arg : args) { - if (arg instanceof BaseHttpRequestOptions) { - for (Map.Entry httpEntry : ((BaseHttpRequestOptions) arg).buildFormParameters().entries()) { - argStrings.add(httpEntry.getKey() + "=" + httpEntry.getValue()); - } - argValues.add(arg); - } else { - Map.Entry entry = (Map.Entry) arg; - argStrings.add(entry.getKey() + "=" + Strings2.urlEncode(entry.getValue())); - argValues.add(entry.getValue()); - } - } - - Method method = null; - for (Method m : asyncClientClass.getMethods()) { - if (m.getName().equals(localMethod)) { - assertNull(method, "More than one method called " + localMethod + " in class " + asyncClientClass); - method = m; - } - } - - assertNotNull(method, "Failed to locate method " + localMethod + " in class " + asyncClientClass); - - HttpRequest httpRequest = processor.createRequest(method, argValues.toArray()); - - assertRequestLineEquals(httpRequest, httpMethod + " https://api.glesys.com/" + remoteServicePrefix + "/" + remoteCall + "/format/json HTTP/1.1"); - - if (expectResponse) { - assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n"); - assertResponseParserClassEquals(method, httpRequest, responseParser); - } - - if (argStrings.isEmpty()) { - assertPayloadEquals(httpRequest, null, null, false); - } else { - assertNotNull(httpRequest.getPayload()); - String payload = (String) httpRequest.getPayload().getRawContent(); - Iterable in = Splitter.on("&").split(payload); - assertContentHeadersEqual(httpRequest, "application/x-www-form-urlencoded", null, null, null, 0L + payload.length(), null); - assertEquals(ImmutableSortedSet.copyOf(in), ImmutableSortedSet.copyOf(argStrings)); - - } - - assertSaxResponseParserClassEquals(method, null); - assertExceptionParserClassEquals(method, exceptionParser); - - checkFilters(httpRequest); - } - } diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java new file mode 100644 index 0000000000..5e7f0e02ca --- /dev/null +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java @@ -0,0 +1,115 @@ +/** + * 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.glesys.features; + +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import org.jclouds.glesys.GleSYSClient; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.options.BaseHttpRequestOptions; +import org.jclouds.io.payloads.StringPayload; +import org.jclouds.rest.BaseRestClientExpectTest; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; + +/** + * Support for short-hand generation of ClientExpectTests for the GleSYS clients + * + * @author Adam Lowe + */ +public abstract class BaseGleSYSClientExpectTest extends BaseRestClientExpectTest { + protected String remoteServicePrefix; + + public BaseGleSYSClientExpectTest() { + provider = "glesys"; + } + + protected abstract T getClient(GleSYSClient gleSYSClient); + + protected Map.Entry entry(String key, Object value) { + return Maps.immutableEntry(key, value.toString()); + } + + /** + * Build a mock of a GleSYS client that responds as instructed + * + * @param remoteCall the name of the expected call on the remote server + * @param httpMethod "GET" or "POST" + * @param returnCode the http status code expected (ordinarily 200) + * @param expectedResponse ensure this is not-null for calls that expect a response - for OK responses this should be + * the classpath location of a file with a valid server response, for errors any String + * @param args either Map.Entry or BaseHttpRequestOption objects that make up the arguments to the method + * @return the appropriate client for test to invoke methods on (by calling getClient() in the appropriate subclass) + */ + @SuppressWarnings("unchecked") + protected T createMock(String remoteCall, String httpMethod, int returnCode, String expectedResponse, Object... args) throws Exception { + List argValues = new ArrayList(); + + Multimap map = LinkedHashMultimap.create(); + + for (Object arg : args) { + if (arg instanceof BaseHttpRequestOptions) { + for (Map.Entry httpEntry : ((BaseHttpRequestOptions) arg).buildFormParameters().entries()) { + map.put(httpEntry.getKey(), httpEntry.getValue()); + } + argValues.add(arg); + } else { + Map.Entry entry = (Map.Entry) arg; + map.put(entry.getKey(), entry.getValue()); + argValues.add(entry.getValue()); + } + } + + HttpRequest.Builder httpRequestBuilder = HttpRequest.builder().method(httpMethod).endpoint( + URI.create("https://api.glesys.com/" + remoteServicePrefix + "/" + remoteCall + "/format/json")); + + if (expectedResponse == null) { + httpRequestBuilder.headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()); + } else { + httpRequestBuilder.headers(ImmutableMultimap.builder() + .put("Accept", "application/json").put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()); + } + + if (!map.isEmpty()) { + httpRequestBuilder.payload(newUrlEncodedFormPayload( + ImmutableMultimap.builder().putAll(map).build())); + } + + HttpResponse.Builder responseBuilder = HttpResponse.builder().statusCode(returnCode); + + if (expectedResponse != null) { + if (returnCode < 300) { + responseBuilder.payload(payloadFromResource(expectedResponse)); + } else { + responseBuilder.payload(new StringPayload(expectedResponse)); + } + } + + return getClient(requestSendsResponse(httpRequestBuilder.build(), responseBuilder.build())); + } +} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java deleted file mode 100644 index 78dcafa6bc..0000000000 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainAsyncClientTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * 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.glesys.features; - -import java.util.Map; - -import org.jclouds.glesys.options.DomainOptions; -import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions; -import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; -import org.jclouds.rest.internal.RestAnnotationProcessor; -import org.testng.annotations.Test; - -import com.google.inject.TypeLiteral; - -/** - * Tests annotation parsing of {@code DomainAsyncClient} - * - * @author Adam Lowe - */ -@Test(groups = "unit", testName = "DomainAsyncClientTest") -public class DomainAsyncClientTest extends BaseGleSYSAsyncClientTest { - public DomainAsyncClientTest() { - asyncClientClass = DomainAsyncClient.class; - remoteServicePrefix = "domain"; - } - - private Map.Entry domainName = newEntry("domain", "cl666666someuser"); - - public void testListDomains() throws Exception { - testMethod("listDomains", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class); - } - - public void testAddDomain() throws Exception { - testMethod("addDomain", "add", "POST", false, MapHttp4xxCodesToExceptions.class, newEntry("name", "cl66666_x"), - DomainOptions.Builder.primaryNameServer("ns1.somewhere.x").expire(1).minimum(1).refresh(1). - responsiblePerson("Tester").retry(1).ttl(1)); - testMethod("addDomain", "add", "POST", false, MapHttp4xxCodesToExceptions.class, newEntry("name", "cl66666_x")); - } - - public void testEditDomain() throws Exception { - testMethod("editDomain", "edit", "POST", false, MapHttp4xxCodesToExceptions.class, newEntry("domain", "x")); - } - - public void testDeleteDomain() throws Exception { - testMethod("deleteDomain", "delete", "POST", false, MapHttp4xxCodesToExceptions.class, domainName); - } - - @Override - protected TypeLiteral> createTypeLiteral() { - return new TypeLiteral>() { - }; - } -} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java new file mode 100644 index 0000000000..446413102a --- /dev/null +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java @@ -0,0 +1,84 @@ +/** + * 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.glesys.features; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.glesys.GleSYSClient; +import org.jclouds.glesys.domain.Domain; +import org.jclouds.glesys.options.DomainAddOptions; +import org.jclouds.rest.ResourceNotFoundException; +import org.testng.annotations.Test; + +import java.text.SimpleDateFormat; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +/** + * Tests annotation parsing of {@code DomainAsyncClient} + * + * @author Adam Lowe + */ +@Test(groups = "unit", testName = "DomainAsyncClientTest") +public class DomainClientExpectTest extends BaseGleSYSClientExpectTest { + public DomainClientExpectTest() { + remoteServicePrefix = "domain"; + } + + public void testListDomains() throws Exception { + DomainClient client = createMock("list", "POST", 200, "/domain_list.json"); + assertEquals(client.listDomains(), ImmutableSet.of( + Domain.builder().domain("adamlowe.net").createTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2011-12-20 10:58:51")).build() + )); + + // check not found response + client = createMock("list", "POST", 404, "/domain_list.json"); + assertTrue(client.listDomains().isEmpty()); + } + + public void testAddDomain() throws Exception { + createMock("add", "POST", 200, null, entry("name", "cl66666_x")).addDomain("cl66666_x"); + DomainAddOptions options = (DomainAddOptions) DomainAddOptions.Builder.primaryNameServer("ns1.somewhere.x").expire(1).minimum(1).refresh(1). + responsiblePerson("Tester").retry(1).ttl(1); createMock("add", "POST", 200, null, entry("name", "cl66666_x")); + createMock("add", "POST", 200, null, entry("name", "cl66666_x"), options).addDomain("cl66666_x", options); + } + + public void testEditDomain() throws Exception { + createMock("edit", "POST", 200, null, entry("domain", "x")).editDomain("x"); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testEditDomainNotFound() throws Exception { + createMock("edit", "POST", 404, null, entry("domain", "x")).editDomain("x"); + } + + public void testDeleteDomain() throws Exception { + createMock("delete", "POST", 200, null, entry("domain", "cl666666someuser")).deleteDomain("cl666666someuser"); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testDeleteDomainNotFound() throws Exception { + createMock("delete", "POST", 404, null, entry("domain", "cl666666someuser")).deleteDomain("cl666666someuser"); + } + + @Override + protected DomainClient getClient(GleSYSClient gleSYSClient) { + return gleSYSClient.getDomainClient(); + } +} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAsyncClientTest.java deleted file mode 100644 index 84fb0cae0d..0000000000 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAsyncClientTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * 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.glesys.features; - -import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions; -import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; -import org.jclouds.rest.internal.RestAnnotationProcessor; -import org.testng.annotations.Test; - -import com.google.inject.TypeLiteral; - -/** - * Tests annotation parsing of {@code ArchiveAsyncClient} - * - * @author Adam Lowe - */ -@Test(groups = "unit", testName = "EmailAsyncClientTest") -public class EmailAsyncClientTest extends BaseGleSYSAsyncClientTest { - public EmailAsyncClientTest() { - asyncClientClass = EmailAsyncClient.class; - remoteServicePrefix = "email"; - } - - public void testList() throws Exception { - testMethod("listAccounts", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class, newEntry("domain","test")); - } - - public void testOverview() throws Exception { - testMethod("getEmailOverview", "overview", "POST", true, ReturnEmptySetOnNotFoundOr404.class); - } - - public void testCreateAccount() throws Exception { - testMethod("createAccount", "createaccount", "POST", false, MapHttp4xxCodesToExceptions.class, - newEntry("emailaccount", "jclouds.org"), newEntry("password", "test@jclouds.org")); - } - - public void testCreateAlias() throws Exception { - testMethod("createAlias", "createalias", "POST", false, MapHttp4xxCodesToExceptions.class, - newEntry("emailalias", "test2@jclouds.org"), newEntry("goto", "test@jclouds.org")); - } - - public void testEditAlias() throws Exception { - testMethod("editAlias", "editalias", "POST", false, MapHttp4xxCodesToExceptions.class, - newEntry("emailalias", "test2@jclouds.org"), newEntry("goto", "test1@jclouds.org")); - } - - @Override - protected TypeLiteral> createTypeLiteral() { - return new TypeLiteral>() { - }; - } -} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java new file mode 100644 index 0000000000..57de0677f0 --- /dev/null +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java @@ -0,0 +1,116 @@ +/** + * 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.glesys.features; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.glesys.GleSYSClient; +import org.jclouds.glesys.domain.Email; +import org.jclouds.glesys.domain.EmailOverview; +import org.jclouds.glesys.domain.EmailOverviewDomain; +import org.jclouds.glesys.domain.EmailOverviewSummary; +import org.jclouds.rest.ResourceNotFoundException; +import org.testng.annotations.Test; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Set; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +/** + * Tests annotation parsing of {@code ArchiveAsyncClient} + * + * @author Adam Lowe + */ +@Test(groups = "unit", testName = "EmailAsyncClientTest") +public class EmailClientExpectTest extends BaseGleSYSClientExpectTest { + public EmailClientExpectTest() { + remoteServicePrefix = "email"; + } + + public void testList() throws Exception { + EmailClient client = createMock("list", "POST", 200, "/email_list.json", entry("domain", "test")); + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + Email.Builder builder = Email.builder().quota("200 MB").usedQuota("0 MB").antispamLevel(3).antiVirus(true).autoRespond(false).autoRespondSaveEmail(true).autoRespondMessage("false"); + Set expected = + ImmutableSet.of( + builder.account("test@adamlowe.net").created(dateFormat.parse("2011-12-22T12:13:14")).modified(dateFormat.parse("2011-12-22T12:13:35")).build(), + builder.account("test2@adamlowe.net").created(dateFormat.parse("2011-12-22T12:14:29")).modified(dateFormat.parse("2011-12-22T12:14:31")).build() + ); + assertEquals(client.listAccounts("test"), expected); + + // check not found response + client = createMock("list", "POST", 404, "Domain not found", entry("domain", "test")); + assertTrue(client.listAccounts("test").isEmpty()); + } + + public void testOverview() throws Exception { + EmailClient client = createMock("overview", "POST", 200, "/email_overview.json"); + + EmailOverviewSummary summary = EmailOverviewSummary.builder().accounts(2).maxAccounts(50).aliases(0).maxAliases(1000).build(); + EmailOverviewDomain domain = EmailOverviewDomain.builder().domain("adamlowe.net").accounts(2).aliases(0).build(); + EmailOverview expected = EmailOverview.builder().summary(summary).domains(domain).build(); + + assertEquals(client.getEmailOverview(), expected); + + assertNull(createMock("overview", "POST", 404, "Not found").getEmailOverview()); + } + + public void testCreateAccount() throws Exception { + createMock("createaccount", "POST", 200, null, + entry("emailaccount", "test@jclouds.org"), entry("password", "newpass")).createAccount("test@jclouds.org", "newpass"); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testCreateAccountDomainNotFound() throws Exception { + createMock("createaccount", "POST", 404, null, + entry("emailaccount", "test@jclouds.org"), entry("password", "newpass")).createAccount("test@jclouds.org", "newpass"); + } + + + public void testCreateAlias() throws Exception { + createMock("createalias", "POST", 200, null, + entry("emailalias", "test2@jclouds.org"), entry("goto", "test@jclouds.org")).createAlias("test2@jclouds.org", "test@jclouds.org"); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testCreateAliasNotFound() throws Exception { + createMock("createalias", "POST", 404, null, + entry("emailalias", "test2@jclouds.org"), entry("goto", "test@jclouds.org")).createAlias("test2@jclouds.org", "test@jclouds.org"); + } + + public void testEditAlias() throws Exception { + createMock("editalias", "POST", 200, null, + entry("emailalias", "test2@jclouds.org"), entry("goto", "test1@jclouds.org")).editAlias("test2@jclouds.org", "test1@jclouds.org"); + } + + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testEditAliasNotFound() throws Exception { + createMock("editalias", "POST", 404, null, + entry("emailalias", "test2@jclouds.org"), entry("goto", "test1@jclouds.org")).editAlias("test2@jclouds.org", "test1@jclouds.org"); + } + + @Override + protected EmailClient getClient(GleSYSClient gleSYSClient) { + return gleSYSClient.getEmailClient(); + } +} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerAsyncClientTest.java deleted file mode 100644 index 283c622c6e..0000000000 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerAsyncClientTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/** - * 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.glesys.features; - -import java.util.Map; - -import org.jclouds.glesys.functions.ParseServerTemplatesFromHttpResponse; -import org.jclouds.glesys.options.ServerCloneOptions; -import org.jclouds.glesys.options.ServerCreateOptions; -import org.jclouds.glesys.options.ServerDestroyOptions; -import org.jclouds.glesys.options.ServerEditOptions; -import org.jclouds.glesys.options.ServerStatusOptions; -import org.jclouds.glesys.options.ServerStopOptions; -import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions; -import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; -import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; -import org.jclouds.rest.internal.RestAnnotationProcessor; -import org.testng.annotations.Test; - -import com.google.inject.TypeLiteral; - -/** - * Tests annotation parsing of {@code ServerAsyncClient} - * - * @author Adrian Cole - * @author Adam Lowe - */ -@Test(groups = "unit", testName = "ServerAsyncClientTest") -public class ServerAsyncClientTest extends BaseGleSYSAsyncClientTest { - - public ServerAsyncClientTest() { - asyncClientClass = ServerAsyncClient.class; - remoteServicePrefix = "server"; - } - - private Map.Entry serverIdOnly = newEntry("serverid", "abcd"); - - public void testListServers() throws Exception { - testMethod("listServers", "list", "POST", true, ReturnEmptySetOnNotFoundOr404.class); - } - - public void testGetAllowedArguments() throws Exception { - testMethod("getServerAllowedArguments", "allowedarguments", "GET", true, MapHttp4xxCodesToExceptions.class); - } - - public void testGetTemplates() throws Exception { - testMethod("getTemplates", "templates", "GET", true, ParseServerTemplatesFromHttpResponse.class, - MapHttp4xxCodesToExceptions.class); - } - - public void testGetServer() throws Exception { - testMethod("getServerDetails", "details", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly); - } - - @Test - public void testCreateServer() throws Exception { - testMethod("createServer", "create", "POST", true, MapHttp4xxCodesToExceptions.class, - newEntry("datacenter", "Falkenberg"), newEntry("platform", "OpenVZ"), - newEntry("hostname", "jclouds-test"), newEntry("template", "Ubuntu%2032-bit"), - newEntry("disksize", 5), newEntry("memorysize", 512), newEntry("cpucores", 1), - newEntry("rootpw", "password"), newEntry("transfer", 50)); - testMethod("createServer", "create", "POST", true, MapHttp4xxCodesToExceptions.class, - newEntry("datacenter", "Falkenberg"), newEntry("platform", "OpenVZ"), - newEntry("hostname", "jclouds-test"), newEntry("template", "Ubuntu%2032-bit"), - newEntry("disksize", 5), newEntry("memorysize", 512), newEntry("cpucores", 1), - newEntry("rootpw", "password"), newEntry("transfer", 50), - ServerCreateOptions.Builder.description("Description-of-server").ip("10.0.0.1")); - } - - @Test - public void testEditServer() throws Exception { - testMethod("editServer", "edit", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly); - testMethod("editServer", "edit", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, - ServerEditOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test")); - } - - @Test - public void testCloneServer() throws Exception { - testMethod("cloneServer", "clone", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, newEntry("hostname", "somename")); - testMethod("cloneServer", "clone", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, newEntry("hostname", "somename"), - ServerCloneOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test")); - } - - public void testGetServerStatus() throws Exception { - testMethod("getServerStatus", "status", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly); - testMethod("getServerStatus", "status", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly, ServerStatusOptions.Builder.state()); - } - - public void testGetServerLimits() throws Exception { - testMethod("getServerLimits", "limits", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly); - } - - public void testGetServerConsole() throws Exception { - testMethod("getServerConsole", "console", "POST", true, ReturnNullOnNotFoundOr404.class, serverIdOnly); - } - - public void testStartServer() throws Exception { - testMethod("startServer", "start", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly); - } - - public void testStopServer() throws Exception { - testMethod("stopServer", "stop", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly); - testMethod("stopServer", "stop", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, ServerStopOptions.Builder.hard()); - } - - public void testRebootServer() throws Exception { - testMethod("rebootServer", "reboot", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly); - } - - public void testDestroyServer() throws Exception { - testMethod("destroyServer", "destroy", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, ServerDestroyOptions.Builder.keepIp()); - testMethod("destroyServer", "destroy", "POST", false, MapHttp4xxCodesToExceptions.class, serverIdOnly, ServerDestroyOptions.Builder.discardIp()); - } - - @Override - protected TypeLiteral> createTypeLiteral() { - return new TypeLiteral>() { - }; - } -} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java new file mode 100644 index 0000000000..8e00e2ca04 --- /dev/null +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java @@ -0,0 +1,158 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.glesys.features; + +import java.util.Map; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.glesys.GleSYSClient; +import org.jclouds.glesys.domain.*; +import org.jclouds.glesys.options.ServerCloneOptions; +import org.jclouds.glesys.options.ServerCreateOptions; +import org.jclouds.glesys.options.ServerDestroyOptions; +import org.jclouds.glesys.options.ServerEditOptions; +import org.jclouds.glesys.options.ServerStatusOptions; +import org.jclouds.glesys.options.ServerStopOptions; +import org.jclouds.glesys.parse.ParseServerAllowedArgumentsTest; +import org.jclouds.glesys.parse.ParseServerDetailsTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +/** + * Tests annotation parsing of {@code ServerAsyncClient} + * + * @author Adrian Cole + * @author Adam Lowe + */ +@Test(groups = "unit", testName = "ServerAsyncClientTest") +public class ServerClientExpectTest extends BaseGleSYSClientExpectTest { + + public ServerClientExpectTest() { + remoteServicePrefix = "server"; + } + + private final String serverId = "abcd"; + private final Map.Entry serverIdOnly = entry("serverid", serverId); + + public void testListServers() throws Exception { + ServerClient client = createMock("list", "POST", 200, "/server_list.json"); + Server expected = Server.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ").build(); + assertEquals(client.listServers(), ImmutableSet.of(expected)); + + // check we get empty set, if not-found + assertTrue(createMock("list", "POST", 404, "Not found").listServers().isEmpty()); + } + + public void testGetAllowedArguments() throws Exception { + ServerClient client = createMock("allowedarguments", "GET", 200, "/server_allowed_arguments.json"); + assertEquals(client.getServerAllowedArguments(), ParseServerAllowedArgumentsTest.getData()); + } + + public void testGetTemplates() throws Exception { + createMock("templates", "GET", 200, "/server_templates.json"); + } + + public void testGetServer() throws Exception { + ServerClient client = createMock("details", "POST", 200, "/server_details.json", serverIdOnly); + + ServerDetails actual = client.getServerDetails(serverId); + assertEquals(actual, ParseServerDetailsTest.getData()); + assertEquals(actual.toString(), ParseServerDetailsTest.getData().toString()); + } + + @Test + public void testCreateServer() throws Exception { + ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build(); + ServerClient client = createMock("create", "POST", 200, "/server_created.json", + entry("cpucores", 1), entry("memorysize", 512), + entry("datacenter", "Falkenberg"), entry("transfer", 50), + entry("rootpw", "password"), entry("hostname", "jclouds-test"), entry("platform", "OpenVZ"), + entry("template", "Ubuntu 32-bit"), + entry("disksize", 5)); + assertEquals(client.createServer("Falkenberg", "OpenVZ", "jclouds-test", "Ubuntu 32-bit", 5, 512, 1, "password", 50), expected); + + ServerCreateOptions options = ServerCreateOptions.Builder.description("Description-of-server").ip("10.0.0.1"); + client = createMock("create", "POST", 200, "/server_created.json", + entry("cpucores", 1), entry("memorysize", 512), + entry("datacenter", "Falkenberg"), entry("transfer", 50), + entry("rootpw", "password"), entry("hostname", "jclouds-test"), entry("platform", "OpenVZ"), + entry("template", "Ubuntu 32-bit"), + entry("disksize", 5), options); + assertEquals(client.createServer("Falkenberg", "OpenVZ", "jclouds-test", "Ubuntu 32-bit", 5, 512, 1, "password", 50, options), expected); + } + + @Test + public void testEditServer() throws Exception { + createMock("edit", "POST", 200, null, serverIdOnly).editServer(serverId); + ServerEditOptions options = + ServerEditOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test"); + createMock("edit", "POST", 200, null, serverIdOnly, options).editServer(serverId, options); + } + + @Test + public void testCloneServer() throws Exception { + createMock("clone", "POST", 200, "/server_created.json", serverIdOnly, entry("hostname", "somename")).cloneServer(serverId, "somename"); + ServerCloneOptions options = (ServerCloneOptions) ServerCloneOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1); + createMock("clone", "POST", 200, "/server_created.json", serverIdOnly, entry("hostname", "somename"), options).cloneServer(serverId, "somename", options); + } + + public void testGetServerStatus() throws Exception { + createMock("status", "POST", 200, "/server_status.json", serverIdOnly).getServerStatus(serverId); + createMock("status", "POST", 200, "/server_status.json", serverIdOnly, ServerStatusOptions.Builder.state()). + getServerStatus(serverId, ServerStatusOptions.Builder.state()); + createMock("status", "POST", 404, "Not found", serverIdOnly).getServerStatus(serverId); + } + + public void testGetServerLimits() throws Exception { + createMock("limits", "POST", 200, "/server_limits.json", serverIdOnly).getServerLimits(serverId); + assertNull(createMock("limits", "POST", 404, "Not found", serverIdOnly).getServerLimits(serverId)); + } + + public void testGetServerConsole() throws Exception { + createMock("console", "POST", 200, "/server_console.json", serverIdOnly).getServerConsole(serverId); + assertNull(createMock("console", "POST", 404, "Not found", serverIdOnly).getServerConsole(serverId)); + } + + public void testStartServer() throws Exception { + createMock("start", "POST", 200, null, serverIdOnly).startServer(serverId); + } + + public void testStopServer() throws Exception { + createMock("stop", "POST", 200, null, serverIdOnly).stopServer(serverId); + createMock("stop", "POST", 200, null, serverIdOnly, ServerStopOptions.Builder.hard()).stopServer(serverId, ServerStopOptions.Builder.hard()); + } + + public void testRebootServer() throws Exception { + createMock("reboot", "POST", 200, null, serverIdOnly).rebootServer(serverId); + } + + public void testDestroyServer() throws Exception { + createMock("destroy", "POST", 200, null, serverIdOnly, ServerDestroyOptions.Builder.keepIp()).destroyServer(serverId, ServerDestroyOptions.Builder.keepIp()); + createMock("destroy", "POST", 200, null, serverIdOnly, ServerDestroyOptions.Builder.discardIp()).destroyServer(serverId, ServerDestroyOptions.Builder.discardIp()); + } + + @Override + protected ServerClient getClient(GleSYSClient gleSYSClient) { + return gleSYSClient.getServerClient(); + } + +} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java index cebde48f22..ca7cee8fec 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java @@ -47,34 +47,37 @@ public class ParseServerAllowedArgumentsTest extends BaseItemParserTest expected() { - Map result = new LinkedHashMap(); - ServerAllowedArguments openvz = ServerAllowedArguments.builder() - .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm") - .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288) - .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150) - .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) - .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit", - "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit", - "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12", - "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit") - .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) - .build(); - ServerAllowedArguments xen = ServerAllowedArguments.builder() - .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384) - .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300) - .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) - .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64", - "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit", - "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std", - "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web") - .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) - .dataCenters("Falkenberg") - .build(); - result.put("Xen", xen); - result.put("OpenVZ", openvz); - return result; + return getData(); } + public static Map getData() { + Map result = new LinkedHashMap(); + ServerAllowedArguments openvz = ServerAllowedArguments.builder() + .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm") + .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288) + .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150) + .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) + .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit", + "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit", + "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12", + "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit") + .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) + .build(); + ServerAllowedArguments xen = ServerAllowedArguments.builder() + .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384) + .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300) + .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) + .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64", + "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit", + "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std", + "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web") + .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) + .dataCenters("Falkenberg") + .build(); + result.put("Xen", xen); + result.put("OpenVZ", openvz); + return result; + } protected Injector injector() { return Guice.createInjector(new GleSYSParserModule(), new GsonModule()); diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java new file mode 100644 index 0000000000..80e19c035b --- /dev/null +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java @@ -0,0 +1,65 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.glesys.parse; + + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.jclouds.glesys.config.GleSYSParserModule; +import org.jclouds.glesys.domain.Cost; +import org.jclouds.glesys.domain.ServerCreated; +import org.jclouds.glesys.domain.ServerCreatedIp; +import org.jclouds.glesys.domain.ServerDetails; +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +/** + * @author Adam Lowe + */ +@Test(groups = "unit", testName = "ParseServerDetailsTest") +public class ParseServerDetailsTest extends BaseItemParserTest { + + @Override + public String resource() { + return "/server_details.json"; + } + + @Override + @SelectJson("server") + @Consumes(MediaType.APPLICATION_JSON) + public ServerDetails expected() { + return getData(); + } + + public static ServerDetails getData() { + Cost cost = Cost.builder().amount(6.38).currency("EUR").timePeriod("month").build(); + return ServerDetails.builder().id("vz1908384").hostname("jclouds-unit").cpuCores(1). + memory(128).disk(5). + description("unit test server").datacenter("Falkenberg").platform("OpenVZ").cost(cost).build(); + } + + protected Injector injector() { + return Guice.createInjector(new GleSYSParserModule(), new GsonModule()); + } +} diff --git a/sandbox-providers/glesys/src/test/resources/server_details.json b/sandbox-providers/glesys/src/test/resources/server_details.json new file mode 100644 index 0000000000..55ae23ac82 --- /dev/null +++ b/sandbox-providers/glesys/src/test/resources/server_details.json @@ -0,0 +1 @@ +{"response":{"status":{"code":"200","text":"OK"},"server":{"serverid":"vz1908384","hostname":"jclouds-unit","description":"unit test server","cpucores":"1","memory":"128","disk":"5","transfer":"50","template":"Debian 6.0 64-bit","datacenter":"Falkenberg","managedhosting":"no","platform":"OpenVZ","cost":{"amount":6.38,"currency":"EUR","timeperiod":"month"},"iplist":[]},"debug":{"input":{"serverid":"vz1908384"}}}} \ No newline at end of file diff --git a/sandbox-providers/glesys/src/test/resources/server_limits.json b/sandbox-providers/glesys/src/test/resources/server_limits.json new file mode 100644 index 0000000000..6939127b7b --- /dev/null +++ b/sandbox-providers/glesys/src/test/resources/server_limits.json @@ -0,0 +1 @@ +{"response":{"status":{"code":"200","text":"OK"},"limits":{"numiptent":{"held":"24","maxheld":"24","barrier":"800","limit":"800","failcnt":0},"numfile":{"held":"91","maxheld":"140","barrier":"4000","limit":"4000","failcnt":0},"dcachesize":{"held":"695143","maxheld":"724260","barrier":"3500000","limit":"4375000","failcnt":0},"numothersock":{"held":"63","maxheld":"66","barrier":"6000","limit":"6000","failcnt":0},"dgramrcvbuf":{"held":"0","maxheld":"0","barrier":"209715200","limit":"262144000","failcnt":0},"othersockbuf":{"held":"4624","maxheld":"13080","barrier":"209715200","limit":"262144000","failcnt":0},"tcprcvbuf":{"held":"32768","maxheld":"32768","barrier":"209715200","limit":"262144000","failcnt":0},"tcpsndbuf":{"held":"34880","maxheld":"34880","barrier":"209715200","limit":"262144000","failcnt":0},"numsiginfo":{"held":"0","maxheld":"15","barrier":"256","limit":"256","failcnt":0},"numpty":{"held":"0","maxheld":"0","barrier":"32","limit":"32","failcnt":0},"numflock":{"held":"1","maxheld":"2","barrier":"376","limit":"412","failcnt":0},"numtcpsock":{"held":"2","maxheld":"2","barrier":"6000","limit":"6000","failcnt":0},"oomguarpages":{"held":"362","maxheld":"464","barrier":"32768","limit":"32768","failcnt":0},"vmguarpages":{"held":"0","maxheld":"0","barrier":"32768","limit":"32768","failcnt":0},"physpages":{"held":"2056","maxheld":"5194","barrier":"0","limit":"9223372036854775807","failcnt":0},"numproc":{"held":"21","maxheld":"33","barrier":"2000","limit":"2000","failcnt":0},"shmpages":{"held":"0","maxheld":"0","barrier":"512000","limit":"512000","failcnt":0},"privvmpages":{"held":"650","maxheld":"1718","barrier":"32768","limit":"32768","failcnt":0},"lockedpages":{"held":"0","maxheld":"0","barrier":"256","limit":"256","failcnt":0},"kmemsize":{"held":"1964946","maxheld":"2932736","barrier":"7680000","limit":"11520000","failcnt":0}},"debug":{"input":{"serverid":"vz1908384"}}}} \ No newline at end of file From f1a8649c3f7e5fda060e1ba2d72733984148da2f Mon Sep 17 00:00:00 2001 From: Adam Lowe Date: Tue, 10 Jan 2012 10:57:23 +0000 Subject: [PATCH 03/82] Removing erroneously committed files --- .../jclouds/glesys/compute/GleSYSComputeService.java | 11 ----------- .../config/GleSYSComputeServiceContextModule.java | 11 ----------- 2 files changed, 22 deletions(-) delete mode 100644 sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java delete mode 100644 sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java deleted file mode 100644 index 48266e0679..0000000000 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeService.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jclouds.glesys.compute; - -/** - * Created by IntelliJ IDEA. - * User: aplowe - * Date: 09/01/2012 - * Time: 13:03 - * To change this template use File | Settings | File Templates. - */ -public class GleSYSComputeService { -} diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java deleted file mode 100644 index 94b33686bd..0000000000 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jclouds.glesys.compute.config; - -/** - * Created by IntelliJ IDEA. - * User: aplowe - * Date: 09/01/2012 - * Time: 13:05 - * To change this template use File | Settings | File Templates. - */ -public class GleSYSComputeServiceContextModule { -} From 41dedd049895a816ddaca2b3fe3a03e28c8c38b6 Mon Sep 17 00:00:00 2001 From: Adam Lowe Date: Wed, 11 Jan 2012 01:05:56 +0000 Subject: [PATCH 04/82] Re-writing ClientExpectTest in the required format --- .../features/ArchiveClientExpectTest.java | 209 ++++++-- .../features/BaseGleSYSAsyncClientTest.java | 1 - .../features/BaseGleSYSClientExpectTest.java | 115 ----- .../features/DomainClientExpectTest.java | 138 ++++-- .../features/EmailClientExpectTest.java | 179 +++++-- .../features/ServerClientExpectTest.java | 464 ++++++++++++++---- .../ParseServerAllowedArgumentsTest.java | 56 +-- .../glesys/parse/ParseServerDetailsTest.java | 4 - 8 files changed, 814 insertions(+), 352 deletions(-) delete mode 100644 sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java index 524c8b7470..c0e48753c6 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveClientExpectTest.java @@ -19,89 +19,206 @@ package org.jclouds.glesys.features; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMultimap; import org.jclouds.glesys.GleSYSClient; import org.jclouds.glesys.domain.Archive; import org.jclouds.glesys.domain.ArchiveAllowedArguments; import org.jclouds.glesys.domain.ArchiveDetails; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.rest.BaseRestClientExpectTest; import org.jclouds.rest.ResourceNotFoundException; import org.testng.annotations.Test; -import java.util.Map; +import java.net.URI; +import java.util.List; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; import static org.testng.Assert.*; /** - * Tests annotation parsing of {@code ArchiveAsyncClient} + * Tests parsing of {@code ArchiveAsyncClient} * * @author Adam Lowe */ -@Test(groups = "unit", testName = "ArchiveAsyncClientTest") -public class ArchiveClientExpectTest extends BaseGleSYSClientExpectTest { +@Test(groups = "unit", testName = "ArchiveClientExpectTest") +public class ArchiveClientExpectTest extends BaseRestClientExpectTest { public ArchiveClientExpectTest() { - remoteServicePrefix = "archive"; + provider = "glesys"; } - private Map.Entry userName = entry("username", "xxxxxx_test1"); + public void testListArchivesWhenReponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/list/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_list.json")).build()) + .getArchiveClient(); - public void testListArchives() throws Exception { - ArchiveClient client = createMock("list", "POST", 200, "/archive_list.json"); - assertEquals(client.listArchives(), - ImmutableList.of(Archive.builder().username("xxxxx_test1").freeSize("20 GB").totalSize("20 GB").locked(false).build())); + List expected = ImmutableList.of( + Archive.builder().username("xxxxx_test1").freeSize("20 GB").totalSize("20 GB").locked(false).build()); + + assertEquals(client.listArchives(), expected); + } + + public void testListArchivesWhenResponseIs4xxReturnsEmpty() { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/list/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(), + HttpResponse.builder().statusCode(404).build()).getArchiveClient(); - // check not found response - client = createMock("list", "POST", 404, "Something not found"); assertTrue(client.listArchives().isEmpty()); } - public void testArchiveDetails() throws Exception { - assertEquals(createMock("details", "POST", 200, "/archive_details.json", userName).getArchiveDetails("xxxxxx_test1"), - ArchiveDetails.builder().username("xxxxxx_test1").freeSize("30 GB").totalSize("30 GB").locked(false).build()); - assertNull(createMock("details", "POST", 404, "/archive_details.json", userName).getArchiveDetails("xxxxxx_test1")); + public void testArchiveDetailsWhenResponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/details/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload( + ImmutableMultimap.builder().put("username", "xxxxxx_test1").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build()) + .getArchiveClient(); + ArchiveDetails expected = ArchiveDetails.builder().username("xxxxxx_test1").freeSize("30 GB").totalSize("30 GB").locked(false).build(); + + assertEquals(client.getArchiveDetails("xxxxxx_test1"), expected); } - public void testCreateArchive() throws Exception { - createMock("create", "POST", 200, null, userName, entry("size", 5), - entry("password", "somepass")).createArchive(userName.getValue(), "somepass", 5); + public void testArchiveDetailsWhenResponseIs4xxReturnsNull() { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/details/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload( + ImmutableMultimap.builder().put("username", "xxxxxx_test1").build())).build(), + HttpResponse.builder().statusCode(404).build()) + .getArchiveClient(); + assertNull(client.getArchiveDetails("xxxxxx_test1")); } - public void testDeleteArchive() throws Exception { - createMock("delete", "POST", 200, null, userName).deleteArchive(userName.getValue()); + public void testCreateArchiveWhenResponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/create/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("username", "xxxxxx_test1") + .put("size", "5") + .put("password", "somepass").build())).build(), + HttpResponse.builder().statusCode(200).build()).getArchiveClient(); + client.createArchive("xxxxxx_test1", "somepass", 5); + } + + public void testDeleteArchiveWhenResponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/delete/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("username", "xxxxxx_test1").build())).build(), + HttpResponse.builder().statusCode(200).build()).getArchiveClient(); + + client.deleteArchive("xxxxxx_test1"); + } + + @Test(expectedExceptions = {HttpResponseException.class}) + public void testDeleteArchiveWhenResponseIs4xxThrows() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/delete/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("username", "xxxxxx_test1").build())).build(), + HttpResponse.builder().statusCode(402).build()).getArchiveClient(); + client.deleteArchive("xxxxxx_test1"); + } + + public void testResizeArchiveWhenResponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/resize/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("username", "username1") + .put("size", "5").build())).build(), + HttpResponse.builder().statusCode(200).build()).getArchiveClient(); + + client.resizeArchive("username1", 5); } @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testDeleteArchiveNotFound() throws Exception { - createMock("delete", "POST", 404, null, userName).deleteArchive(userName.getValue()); + public void testResizeArchiveWhenResponseIs4xxThrows() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/archive/resize/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("username", "username1") + .put("size", "5").build())).build(), + HttpResponse.builder().statusCode(404).build()).getArchiveClient(); + + client.resizeArchive("username1", 5); } - public void testResizeArchive() throws Exception { - createMock("resize", "POST", 200, null, entry("username", "username"), - entry("size", "5")).resizeArchive("username", 5); + public void testChangeArchivePasswordWhenResponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST") + .endpoint(URI.create("https://api.glesys.com/archive/changepassword/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("username", "username") + .put("password", "newpass").build())).build(), + HttpResponse.builder().statusCode(200).build()).getArchiveClient(); + + client.changeArchivePassword("username", "newpass"); } @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testResizeArchiveNotFound() throws Exception { - createMock("resize", "POST", 404, null, entry("username", "username"), entry("size", "5")).resizeArchive("username", 5); - } - - public void testChangeArchivePassword() throws Exception { - createMock("changepassword", "POST", 200, null, userName, - entry("password", "newpass")).changeArchivePassword(userName.getValue(), "newpass"); + public void testChangeArchivePasswordWhenResponseIs4xxThrows() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("POST") + .endpoint(URI.create("https://api.glesys.com/archive/changepassword/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("username", "username") + .put("password", "newpass").build())).build(), + HttpResponse.builder().statusCode(404).build()).getArchiveClient(); + + client.changeArchivePassword("username", "newpass"); } - @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testChangeArchivePasswordNotFound() throws Exception { - createMock("changepassword", "POST", 404, null, userName, - entry("password", "newpass")).changeArchivePassword(userName.getValue(), "newpass"); - } - - public void testGetArchiveAllowedArguments() throws Exception { - assertEquals(createMock("allowedarguments", "GET", 200, "/archive_allowed_arguments.json").getArchiveAllowedArguments(), - ArchiveAllowedArguments.builder().archiveSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000).build()); - assertNull(createMock("allowedarguments", "GET", 404, "/archive_allowed_arguments.json").getArchiveAllowedArguments()); + public void testGetArchiveAllowedArgumentsWhenResponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("GET") + .endpoint(URI.create("https://api.glesys.com/archive/allowedarguments/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==") + .build()).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_allowed_arguments.json")).build()).getArchiveClient(); + ArchiveAllowedArguments expected = ArchiveAllowedArguments.builder().archiveSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000).build(); + + assertEquals(client.getArchiveAllowedArguments(), expected); } - @Override - protected ArchiveClient getClient(GleSYSClient gleSYSClient) { - return gleSYSClient.getArchiveClient(); + public void testGetArchiveAllowedArguments4xxWhenResponseIs2xx() throws Exception { + ArchiveClient client = requestSendsResponse( + HttpRequest.builder().method("GET") + .endpoint(URI.create("https://api.glesys.com/archive/allowedarguments/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(), + HttpResponse.builder().statusCode(404).build()).getArchiveClient(); + + assertNull(client.getArchiveAllowedArguments()); } } diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java index 43d645325a..e52ef601a7 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSAsyncClientTest.java @@ -45,7 +45,6 @@ import com.google.common.collect.Maps; /** * @author Adrian Cole - * @author Adam Lowe */ public abstract class BaseGleSYSAsyncClientTest extends RestClientTest { diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java deleted file mode 100644 index 5e7f0e02ca..0000000000 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/BaseGleSYSClientExpectTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * 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.glesys.features; - -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import org.jclouds.glesys.GleSYSClient; -import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpResponse; -import org.jclouds.http.options.BaseHttpRequestOptions; -import org.jclouds.io.payloads.StringPayload; -import org.jclouds.rest.BaseRestClientExpectTest; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; - -/** - * Support for short-hand generation of ClientExpectTests for the GleSYS clients - * - * @author Adam Lowe - */ -public abstract class BaseGleSYSClientExpectTest extends BaseRestClientExpectTest { - protected String remoteServicePrefix; - - public BaseGleSYSClientExpectTest() { - provider = "glesys"; - } - - protected abstract T getClient(GleSYSClient gleSYSClient); - - protected Map.Entry entry(String key, Object value) { - return Maps.immutableEntry(key, value.toString()); - } - - /** - * Build a mock of a GleSYS client that responds as instructed - * - * @param remoteCall the name of the expected call on the remote server - * @param httpMethod "GET" or "POST" - * @param returnCode the http status code expected (ordinarily 200) - * @param expectedResponse ensure this is not-null for calls that expect a response - for OK responses this should be - * the classpath location of a file with a valid server response, for errors any String - * @param args either Map.Entry or BaseHttpRequestOption objects that make up the arguments to the method - * @return the appropriate client for test to invoke methods on (by calling getClient() in the appropriate subclass) - */ - @SuppressWarnings("unchecked") - protected T createMock(String remoteCall, String httpMethod, int returnCode, String expectedResponse, Object... args) throws Exception { - List argValues = new ArrayList(); - - Multimap map = LinkedHashMultimap.create(); - - for (Object arg : args) { - if (arg instanceof BaseHttpRequestOptions) { - for (Map.Entry httpEntry : ((BaseHttpRequestOptions) arg).buildFormParameters().entries()) { - map.put(httpEntry.getKey(), httpEntry.getValue()); - } - argValues.add(arg); - } else { - Map.Entry entry = (Map.Entry) arg; - map.put(entry.getKey(), entry.getValue()); - argValues.add(entry.getValue()); - } - } - - HttpRequest.Builder httpRequestBuilder = HttpRequest.builder().method(httpMethod).endpoint( - URI.create("https://api.glesys.com/" + remoteServicePrefix + "/" + remoteCall + "/format/json")); - - if (expectedResponse == null) { - httpRequestBuilder.headers(ImmutableMultimap.builder() - .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()); - } else { - httpRequestBuilder.headers(ImmutableMultimap.builder() - .put("Accept", "application/json").put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()); - } - - if (!map.isEmpty()) { - httpRequestBuilder.payload(newUrlEncodedFormPayload( - ImmutableMultimap.builder().putAll(map).build())); - } - - HttpResponse.Builder responseBuilder = HttpResponse.builder().statusCode(returnCode); - - if (expectedResponse != null) { - if (returnCode < 300) { - responseBuilder.payload(payloadFromResource(expectedResponse)); - } else { - responseBuilder.payload(new StringPayload(expectedResponse)); - } - } - - return getClient(requestSendsResponse(httpRequestBuilder.build(), responseBuilder.build())); - } -} diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java index 446413102a..b51208b08b 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/DomainClientExpectTest.java @@ -18,15 +18,22 @@ */ package org.jclouds.glesys.features; +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import org.jclouds.glesys.GleSYSClient; import org.jclouds.glesys.domain.Domain; import org.jclouds.glesys.options.DomainAddOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.rest.BaseRestClientExpectTest; import org.jclouds.rest.ResourceNotFoundException; import org.testng.annotations.Test; +import java.net.URI; import java.text.SimpleDateFormat; +import java.util.Set; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -35,50 +42,123 @@ import static org.testng.Assert.assertTrue; * * @author Adam Lowe */ -@Test(groups = "unit", testName = "DomainAsyncClientTest") -public class DomainClientExpectTest extends BaseGleSYSClientExpectTest { +@Test(groups = "unit", testName = "DomainClientExpectTest") +public class DomainClientExpectTest extends BaseRestClientExpectTest { public DomainClientExpectTest() { - remoteServicePrefix = "domain"; + provider = "glesys"; } - public void testListDomains() throws Exception { - DomainClient client = createMock("list", "POST", 200, "/domain_list.json"); - assertEquals(client.listDomains(), ImmutableSet.of( - Domain.builder().domain("adamlowe.net").createTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2011-12-20 10:58:51")).build() - )); + public void testListDomainsWhenResponseIs2xx() throws Exception { + //DomainClient client = createMock("list", "POST", 200, "/domain_list.json"); + + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/list/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/domain_list.json")).build()).getDomainClient(); + + Set expected = ImmutableSet.of( + Domain.builder().domain("adamlowe.net").createTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2011-12-20 10:58:51")).build()); + + assertEquals(client.listDomains(), expected); + } + + public void testListDomainsWhenResponseIs4xxReturnsEmpty() throws Exception { + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/list/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .build(), + HttpResponse.builder().statusCode(404).build()).getDomainClient(); - // check not found response - client = createMock("list", "POST", 404, "/domain_list.json"); assertTrue(client.listDomains().isEmpty()); } - public void testAddDomain() throws Exception { - createMock("add", "POST", 200, null, entry("name", "cl66666_x")).addDomain("cl66666_x"); - DomainAddOptions options = (DomainAddOptions) DomainAddOptions.Builder.primaryNameServer("ns1.somewhere.x").expire(1).minimum(1).refresh(1). - responsiblePerson("Tester").retry(1).ttl(1); createMock("add", "POST", 200, null, entry("name", "cl66666_x")); - createMock("add", "POST", 200, null, entry("name", "cl66666_x"), options).addDomain("cl66666_x", options); + public void testAddDomainWhenResponseIs2xx() throws Exception { + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/add/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("name", "cl66666_x").build())).build(), + HttpResponse.builder().statusCode(200).build()).getDomainClient(); + + client.addDomain("cl66666_x"); } - public void testEditDomain() throws Exception { - createMock("edit", "POST", 200, null, entry("domain", "x")).editDomain("x"); + + public void testAddDomainWithOptsWhenResponseIs2xx() throws Exception { + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/add/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("name", "cl66666_x") + .put("primary_ns", "ns1.somewhere.x") + .put("expire", "1") + .put("minimum", "1") + .put("refresh", "1") + .put("resp_person", "Tester.") + .put("retry", "1") + .put("ttl", "1") + .build())).build(), + HttpResponse.builder().statusCode(200).build()).getDomainClient(); + DomainAddOptions options = (DomainAddOptions) DomainAddOptions.Builder.primaryNameServer("ns1.somewhere.x") + .expire(1).minimum(1).refresh(1).responsiblePerson("Tester").retry(1).ttl(1); + + client.addDomain("cl66666_x", options); + } + + public void testEditDomainWhenResponseIs2xx() throws Exception { + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/edit/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("domain", "x").build())).build(), + HttpResponse.builder().statusCode(200).build()).getDomainClient(); + + client.editDomain("x"); } @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testEditDomainNotFound() throws Exception { - createMock("edit", "POST", 404, null, entry("domain", "x")).editDomain("x"); + public void testEditDomainWhenResponseIs4xxThrows() throws Exception { + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/edit/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("domain", "x").build())).build(), + HttpResponse.builder().statusCode(404).build()).getDomainClient(); + + client.editDomain("x"); } - - public void testDeleteDomain() throws Exception { - createMock("delete", "POST", 200, null, entry("domain", "cl666666someuser")).deleteDomain("cl666666someuser"); + + public void testDeleteDomainWhenResponseIs2xx() throws Exception { + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/delete/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("domain", "x").build())).build(), + HttpResponse.builder().statusCode(200).build()).getDomainClient(); + + client.deleteDomain("x"); } @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testDeleteDomainNotFound() throws Exception { - createMock("delete", "POST", 404, null, entry("domain", "cl666666someuser")).deleteDomain("cl666666someuser"); - } - - @Override - protected DomainClient getClient(GleSYSClient gleSYSClient) { - return gleSYSClient.getDomainClient(); + public void testDeleteDomainWhenResponseIs4xxThrows() throws Exception { + DomainClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/domain/delete/format/json")) + .headers(ImmutableMultimap.builder().put( + "Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("domain", "x").build())).build(), + HttpResponse.builder().statusCode(404).build()).getDomainClient(); + + client.deleteDomain("x"); } } diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java index 57de0677f0..ac95aae1d3 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/EmailClientExpectTest.java @@ -18,36 +18,51 @@ */ package org.jclouds.glesys.features; +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import org.jclouds.glesys.GleSYSClient; import org.jclouds.glesys.domain.Email; import org.jclouds.glesys.domain.EmailOverview; import org.jclouds.glesys.domain.EmailOverviewDomain; import org.jclouds.glesys.domain.EmailOverviewSummary; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.BaseRestClientExpectTest; import org.jclouds.rest.ResourceNotFoundException; import org.testng.annotations.Test; +import java.net.URI; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Set; +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; /** - * Tests annotation parsing of {@code ArchiveAsyncClient} - * + * Tests annotation parsing of {@code EmailClient} + * * @author Adam Lowe */ @Test(groups = "unit", testName = "EmailAsyncClientTest") -public class EmailClientExpectTest extends BaseGleSYSClientExpectTest { +public class EmailClientExpectTest extends BaseRestClientExpectTest { public EmailClientExpectTest() { - remoteServicePrefix = "email"; + provider = "glesys"; } - public void testList() throws Exception { - EmailClient client = createMock("list", "POST", 200, "/email_list.json", entry("domain", "test")); + public void testListWhenResponseIs2xx() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/list/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload( + ImmutableMultimap.builder().put("domain", "test").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_list.json")).build()).getEmailClient(); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); Email.Builder builder = Email.builder().quota("200 MB").usedQuota("0 MB").antispamLevel(3).antiVirus(true).autoRespond(false).autoRespondSaveEmail(true).autoRespondMessage("false"); @@ -56,61 +71,141 @@ public class EmailClientExpectTest extends BaseGleSYSClientExpectTestbuilder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload( + ImmutableMultimap.builder().put("domain", "test").build())).build(), + HttpResponse.builder().statusCode(404).build()).getEmailClient(); + assertTrue(client.listAccounts("test").isEmpty()); } - public void testOverview() throws Exception { - EmailClient client = createMock("overview", "POST", 200, "/email_overview.json"); + public void testOverviewWhenResponseIs2xx() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/overview/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_overview.json")).build()).getEmailClient(); EmailOverviewSummary summary = EmailOverviewSummary.builder().accounts(2).maxAccounts(50).aliases(0).maxAliases(1000).build(); EmailOverviewDomain domain = EmailOverviewDomain.builder().domain("adamlowe.net").accounts(2).aliases(0).build(); EmailOverview expected = EmailOverview.builder().summary(summary).domains(domain).build(); - + assertEquals(client.getEmailOverview(), expected); - - assertNull(createMock("overview", "POST", 404, "Not found").getEmailOverview()); } - public void testCreateAccount() throws Exception { - createMock("createaccount", "POST", 200, null, - entry("emailaccount", "test@jclouds.org"), entry("password", "newpass")).createAccount("test@jclouds.org", "newpass"); + public void testOverviewWhenResponseIs404ReturnsNull() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/overview/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .build(), + HttpResponse.builder().statusCode(404).build()).getEmailClient(); + + assertNull(client.getEmailOverview()); + } + + public void testCreateAccountWhenResponseIs2xx() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createaccount/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("emailaccount", "test@jclouds.org") + .put("password", "newpass") + .build())) + .build(), + HttpResponse.builder().statusCode(200).build()).getEmailClient(); + + client.createAccount("test@jclouds.org", "newpass"); } @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testCreateAccountDomainNotFound() throws Exception { - createMock("createaccount", "POST", 404, null, - entry("emailaccount", "test@jclouds.org"), entry("password", "newpass")).createAccount("test@jclouds.org", "newpass"); + public void testCreateAccountWhenResponseIs4xxThrows() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createaccount/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("emailaccount", "test@jclouds.org") + .put("password", "newpass") + .build())) + .build(), + HttpResponse.builder().statusCode(404).build()).getEmailClient(); + + client.createAccount("test@jclouds.org", "newpass"); } - - public void testCreateAlias() throws Exception { - createMock("createalias", "POST", 200, null, - entry("emailalias", "test2@jclouds.org"), entry("goto", "test@jclouds.org")).createAlias("test2@jclouds.org", "test@jclouds.org"); + public void testCreateAliasWhenResponseIs2xx() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createalias/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("emailalias", "test2@jclouds.org") + .put("goto", "test@jclouds.org") + .build())) + .build(), + HttpResponse.builder().statusCode(200).build()).getEmailClient(); + + client.createAlias("test2@jclouds.org", "test@jclouds.org"); + } + + @Test(expectedExceptions = {AuthorizationException.class}) + public void testCreateAliasWhenResponseIs4xxThrows() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/createalias/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("emailalias", "test2@jclouds.org") + .put("goto", "test@jclouds.org") + .build())) + .build(), + HttpResponse.builder().statusCode(401).build()).getEmailClient(); + + client.createAlias("test2@jclouds.org", "test@jclouds.org"); + } + + public void testEditAliasWhenResponseIs2xx() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/editalias/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("emailalias", "test2@jclouds.org") + .put("goto", "test@jclouds.org") + .build())) + .build(), + HttpResponse.builder().statusCode(200).build()).getEmailClient(); + + client.editAlias("test2@jclouds.org", "test@jclouds.org"); } @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testCreateAliasNotFound() throws Exception { - createMock("createalias", "POST", 404, null, - entry("emailalias", "test2@jclouds.org"), entry("goto", "test@jclouds.org")).createAlias("test2@jclouds.org", "test@jclouds.org"); - } + public void testEditAliasWhenResponseIs4xxThrows() throws Exception { + EmailClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/email/editalias/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("emailalias", "test2@jclouds.org") + .put("goto", "test@jclouds.org") + .build())) + .build(), + HttpResponse.builder().statusCode(404).build()).getEmailClient(); - public void testEditAlias() throws Exception { - createMock("editalias", "POST", 200, null, - entry("emailalias", "test2@jclouds.org"), entry("goto", "test1@jclouds.org")).editAlias("test2@jclouds.org", "test1@jclouds.org"); - } - - @Test(expectedExceptions = {ResourceNotFoundException.class}) - public void testEditAliasNotFound() throws Exception { - createMock("editalias", "POST", 404, null, - entry("emailalias", "test2@jclouds.org"), entry("goto", "test1@jclouds.org")).editAlias("test2@jclouds.org", "test1@jclouds.org"); - } - - @Override - protected EmailClient getClient(GleSYSClient gleSYSClient) { - return gleSYSClient.getEmailClient(); + client.editAlias("test2@jclouds.org", "test@jclouds.org"); } } diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java index 8e00e2ca04..4826b52684 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/features/ServerClientExpectTest.java @@ -18,24 +18,26 @@ */ package org.jclouds.glesys.features; -import java.util.Map; - +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import org.jclouds.glesys.GleSYSClient; -import org.jclouds.glesys.domain.*; -import org.jclouds.glesys.options.ServerCloneOptions; -import org.jclouds.glesys.options.ServerCreateOptions; -import org.jclouds.glesys.options.ServerDestroyOptions; -import org.jclouds.glesys.options.ServerEditOptions; -import org.jclouds.glesys.options.ServerStatusOptions; -import org.jclouds.glesys.options.ServerStopOptions; -import org.jclouds.glesys.parse.ParseServerAllowedArgumentsTest; -import org.jclouds.glesys.parse.ParseServerDetailsTest; +import org.jclouds.glesys.domain.Server; +import org.jclouds.glesys.domain.ServerCreated; +import org.jclouds.glesys.domain.ServerCreatedIp; +import org.jclouds.glesys.domain.ServerDetails; +import org.jclouds.glesys.options.*; +import org.jclouds.glesys.parse.*; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.BaseRestClientExpectTest; +import org.jclouds.rest.ResourceNotFoundException; import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; +import java.net.URI; + +import static org.jclouds.io.Payloads.newUrlEncodedFormPayload; +import static org.testng.Assert.*; /** * Tests annotation parsing of {@code ServerAsyncClient} @@ -44,115 +46,407 @@ import static org.testng.Assert.assertTrue; * @author Adam Lowe */ @Test(groups = "unit", testName = "ServerAsyncClientTest") -public class ServerClientExpectTest extends BaseGleSYSClientExpectTest { +public class ServerClientExpectTest extends BaseRestClientExpectTest { public ServerClientExpectTest() { - remoteServicePrefix = "server"; + provider = "glesys"; } - private final String serverId = "abcd"; - private final Map.Entry serverIdOnly = entry("serverid", serverId); - - public void testListServers() throws Exception { - ServerClient client = createMock("list", "POST", 200, "/server_list.json"); + public void testListServersWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/list/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(), + HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_list.json")).build()).getServerClient(); Server expected = Server.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ").build(); + assertEquals(client.listServers(), ImmutableSet.of(expected)); - - // check we get empty set, if not-found - assertTrue(createMock("list", "POST", 404, "Not found").listServers().isEmpty()); - } - - public void testGetAllowedArguments() throws Exception { - ServerClient client = createMock("allowedarguments", "GET", 200, "/server_allowed_arguments.json"); - assertEquals(client.getServerAllowedArguments(), ParseServerAllowedArgumentsTest.getData()); } - public void testGetTemplates() throws Exception { - createMock("templates", "GET", 200, "/server_templates.json"); + public void testListServersWhenReponseIs404IsEmpty() { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/list/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(), + HttpResponse.builder().statusCode(404).build()).getServerClient(); + + assertTrue(client.listServers().isEmpty()); } - public void testGetServer() throws Exception { - ServerClient client = createMock("details", "POST", 200, "/server_details.json", serverIdOnly); + public void testGetAllowedArgumentsWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("GET").endpoint(URI.create("https://api.glesys.com/server/allowedarguments/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(), + HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_allowed_arguments.json")).build()).getServerClient(); - ServerDetails actual = client.getServerDetails(serverId); - assertEquals(actual, ParseServerDetailsTest.getData()); - assertEquals(actual.toString(), ParseServerDetailsTest.getData().toString()); + assertEquals(client.getServerAllowedArguments(), new ParseServerAllowedArgumentsTest().expected()); } - + + public void testGetTemplatesWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("GET").endpoint(URI.create("https://api.glesys.com/server/templates/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_templates.json")).build()).getServerClient(); + + assertEquals(client.getTemplates(), new ParseServerTemplatesTest().expected()); + } + + public void testGetServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/details/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server1ssg-1.1").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerClient(); + + ServerDetails actual = client.getServerDetails("server1ssg-1.1"); + assertEquals(actual.toString(), new ParseServerDetailsTest().expected().toString()); + } + @Test - public void testCreateServer() throws Exception { + public void testCreateServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/create/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("cpucores", "1").put("memorysize", "512") + .put("datacenter", "Falkenberg") + .put("transfer", "50") + .put("rootpw", "password") + .put("hostname", "jclouds-test") + .put("platform", "OpenVZ") + .put("template", "Ubuntu 32-bit") + .put("disksize", "5").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient(); ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build(); - ServerClient client = createMock("create", "POST", 200, "/server_created.json", - entry("cpucores", 1), entry("memorysize", 512), - entry("datacenter", "Falkenberg"), entry("transfer", 50), - entry("rootpw", "password"), entry("hostname", "jclouds-test"), entry("platform", "OpenVZ"), - entry("template", "Ubuntu 32-bit"), - entry("disksize", 5)); + assertEquals(client.createServer("Falkenberg", "OpenVZ", "jclouds-test", "Ubuntu 32-bit", 5, 512, 1, "password", 50), expected); - + } + + public void testCreateServerWithOptsWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/create/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("cpucores", "1").put("memorysize", "512") + .put("datacenter", "Falkenberg") + .put("transfer", "50") + .put("rootpw", "password") + .put("hostname", "jclouds-test") + .put("platform", "OpenVZ") + .put("template", "Ubuntu 32-bit") + .put("disksize", "5") + .put("description", "Description-of-server") + .put("ip", "10.0.0.1").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient(); ServerCreateOptions options = ServerCreateOptions.Builder.description("Description-of-server").ip("10.0.0.1"); - client = createMock("create", "POST", 200, "/server_created.json", - entry("cpucores", 1), entry("memorysize", 512), - entry("datacenter", "Falkenberg"), entry("transfer", 50), - entry("rootpw", "password"), entry("hostname", "jclouds-test"), entry("platform", "OpenVZ"), - entry("template", "Ubuntu 32-bit"), - entry("disksize", 5), options); + ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build(); + assertEquals(client.createServer("Falkenberg", "OpenVZ", "jclouds-test", "Ubuntu 32-bit", 5, 512, 1, "password", 50, options), expected); } @Test - public void testEditServer() throws Exception { - createMock("edit", "POST", 200, null, serverIdOnly).editServer(serverId); - ServerEditOptions options = - ServerEditOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test"); - createMock("edit", "POST", 200, null, serverIdOnly, options).editServer(serverId, options); + public void testEditServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/edit/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server111").build())).build(), + HttpResponse.builder().statusCode(206).build()).getServerClient(); + + client.editServer("server111"); } @Test - public void testCloneServer() throws Exception { - createMock("clone", "POST", 200, "/server_created.json", serverIdOnly, entry("hostname", "somename")).cloneServer(serverId, "somename"); + public void testEditServerWithOptsWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/edit/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server111") + .put("description", "Description-of-server") + .put("disksize", "1") + .put("memorysize", "512") + .put("cpucores", "1") + .put("hostname", "jclouds-test") + .build())).build(), + HttpResponse.builder().statusCode(200).build()).getServerClient(); + + ServerEditOptions options = + ServerEditOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1).hostname("jclouds-test"); + + client.editServer("server111", options); + } + + @Test + public void testCloneServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/clone/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server111") + .put("hostname", "hostname1").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient(); + ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build(); + + assertEquals(client.cloneServer("server111", "hostname1"), expected); + } + + @Test + public void testCloneServerWithOptsWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/clone/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server111") + .put("hostname", "hostname1") + .put("description", "Description-of-server") + .put("disksize", "1") + .put("memorysize", "512") + .put("cpucores", "1").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_created.json")).build()).getServerClient(); ServerCloneOptions options = (ServerCloneOptions) ServerCloneOptions.Builder.description("Description-of-server").disksize(1).memorysize(512).cpucores(1); - createMock("clone", "POST", 200, "/server_created.json", serverIdOnly, entry("hostname", "somename"), options).cloneServer(serverId, "somename", options); + ServerCreated expected = ServerCreated.builder().hostname("jclouds-test").id("xm3630641").ips(ServerCreatedIp.builder().ip("109.74.10.27").build()).build(); + + assertEquals(client.cloneServer("server111", "hostname1", options), expected); } - public void testGetServerStatus() throws Exception { - createMock("status", "POST", 200, "/server_status.json", serverIdOnly).getServerStatus(serverId); - createMock("status", "POST", 200, "/server_status.json", serverIdOnly, ServerStatusOptions.Builder.state()). - getServerStatus(serverId, ServerStatusOptions.Builder.state()); - createMock("status", "POST", 404, "Not found", serverIdOnly).getServerStatus(serverId); + @Test(expectedExceptions = {ResourceNotFoundException.class}) + public void testCloneServerWhenResponseIs4xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/clone/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server111") + .put("hostname", "hostname1").build())).build(), + HttpResponse.builder().statusCode(404).build()).getServerClient(); + + client.cloneServer("server111", "hostname1"); } - public void testGetServerLimits() throws Exception { - createMock("limits", "POST", 200, "/server_limits.json", serverIdOnly).getServerLimits(serverId); - assertNull(createMock("limits", "POST", 404, "Not found", serverIdOnly).getServerLimits(serverId)); + public void testGetServerStatusWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/status/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server111").build())).build(), + HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build()) + .getServerClient(); + + assertEquals(client.getServerStatus("server111"), new ParseServerStatusTest().expected()); } - public void testGetServerConsole() throws Exception { - createMock("console", "POST", 200, "/server_console.json", serverIdOnly).getServerConsole(serverId); - assertNull(createMock("console", "POST", 404, "Not found", serverIdOnly).getServerConsole(serverId)); + public void testGetServerStatusWithOptsWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/status/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server321").put("statustype", "state").build())).build(), + HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build()) + .getServerClient(); + + assertEquals(client.getServerStatus("server321", ServerStatusOptions.Builder.state()), new ParseServerStatusTest().expected()); } - public void testStartServer() throws Exception { - createMock("start", "POST", 200, null, serverIdOnly).startServer(serverId); - } - - public void testStopServer() throws Exception { - createMock("stop", "POST", 200, null, serverIdOnly).stopServer(serverId); - createMock("stop", "POST", 200, null, serverIdOnly, ServerStopOptions.Builder.hard()).stopServer(serverId, ServerStopOptions.Builder.hard()); + public void testGetServerStatusWhenResponseIs4xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/status/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server321").put("statustype", "state").build())).build(), + HttpResponse.builder().statusCode(404).build()) + .getServerClient(); + + assertNull(client.getServerStatus("server321", ServerStatusOptions.Builder.state())); } - public void testRebootServer() throws Exception { - createMock("reboot", "POST", 200, null, serverIdOnly).rebootServer(serverId); + public void testGetServerLimitsWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/limits/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server321").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_limits.json")).build()) + .getServerClient(); + + client.getServerLimits("server321"); } - public void testDestroyServer() throws Exception { - createMock("destroy", "POST", 200, null, serverIdOnly, ServerDestroyOptions.Builder.keepIp()).destroyServer(serverId, ServerDestroyOptions.Builder.keepIp()); - createMock("destroy", "POST", 200, null, serverIdOnly, ServerDestroyOptions.Builder.discardIp()).destroyServer(serverId, ServerDestroyOptions.Builder.discardIp()); + public void testGetServerConsoleWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/console/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server322").build())).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_console.json")).build()) + .getServerClient(); + + assertEquals(client.getServerConsole("server322"), new ParseServerConsoleTest().expected()); } - @Override - protected ServerClient getClient(GleSYSClient gleSYSClient) { - return gleSYSClient.getServerClient(); + public void testGetServerConsoleWhenResponseIs4xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/console/format/json")) + .headers(ImmutableMultimap.builder() + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server322").build())).build(), + HttpResponse.builder().statusCode(404).build()) + .getServerClient(); + + assertNull(client.getServerConsole("server322")); + } + + public void testStartServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/start/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").build())).build(), + HttpResponse.builder().statusCode(200).build()) + .getServerClient(); + + client.startServer("server777"); + } + + @Test(expectedExceptions = {AuthorizationException.class}) + public void testStartServerWhenResponseIs4xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/start/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").build())).build(), + HttpResponse.builder().statusCode(401).build()) + .getServerClient(); + + client.startServer("server777"); + } + + public void testStopServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/stop/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").build())).build(), + HttpResponse.builder().statusCode(200).build()) + .getServerClient(); + + client.stopServer("server777"); + } + + public void testHardStopServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/stop/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").put("type", "hard").build())).build(), + HttpResponse.builder().statusCode(200).build()) + .getServerClient(); + + client.stopServer("server777", ServerStopOptions.Builder.hard()); + } + + @Test(expectedExceptions = {AuthorizationException.class}) + public void testStopServerWhenResponseIs4xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/stop/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").build())).build(), + HttpResponse.builder().statusCode(401).build()) + .getServerClient(); + + client.stopServer("server777"); + } + + public void testRebootServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/reboot/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").build())).build(), + HttpResponse.builder().statusCode(200).build()) + .getServerClient(); + + client.rebootServer("server777"); + } + + @Test(expectedExceptions = {AuthorizationException.class}) + public void testRebootServerWhenResponseIs4xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/reboot/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").build())).build(), + HttpResponse.builder().statusCode(401).build()) + .getServerClient(); + + client.rebootServer("server777"); + } + + public void testDestroyServerWhenResponseIs2xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/destroy/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").put("keepip", "1").build())).build(), + HttpResponse.builder().statusCode(200).build()) + .getServerClient(); + + client.destroyServer("server777", ServerDestroyOptions.Builder.keepIp()); + } + + @Test(expectedExceptions = {AuthorizationException.class}) + public void testDestroyServerWhenResponseIs4xx() throws Exception { + ServerClient client = requestSendsResponse( + HttpRequest.builder().method("POST").endpoint(URI.create("https://api.glesys.com/server/destroy/format/json")) + .headers(ImmutableMultimap.builder() + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()) + .payload(newUrlEncodedFormPayload(ImmutableMultimap.builder() + .put("serverid", "server777").put("keepip", "0").build())).build(), + HttpResponse.builder().statusCode(401).build()) + .getServerClient(); + + client.destroyServer("server777", ServerDestroyOptions.Builder.discardIp()); } } diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java index ca7cee8fec..7d1c4810f9 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerAllowedArgumentsTest.java @@ -47,38 +47,34 @@ public class ParseServerAllowedArgumentsTest extends BaseItemParserTest expected() { - return getData(); + Map result = new LinkedHashMap(); + ServerAllowedArguments openvz = ServerAllowedArguments.builder() + .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm") + .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288) + .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150) + .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) + .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit", + "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit", + "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12", + "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit") + .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) + .build(); + ServerAllowedArguments xen = ServerAllowedArguments.builder() + .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384) + .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300) + .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) + .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64", + "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit", + "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std", + "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web") + .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) + .dataCenters("Falkenberg") + .build(); + result.put("Xen", xen); + result.put("OpenVZ", openvz); + return result; } - public static Map getData() { - Map result = new LinkedHashMap(); - ServerAllowedArguments openvz = ServerAllowedArguments.builder() - .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm") - .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288) - .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150) - .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) - .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit", - "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit", - "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12", - "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit") - .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) - .build(); - ServerAllowedArguments xen = ServerAllowedArguments.builder() - .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384) - .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300) - .cpuCores(1, 2, 3, 4, 5, 6, 7, 8) - .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64", - "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit", - "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std", - "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web") - .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000) - .dataCenters("Falkenberg") - .build(); - result.put("Xen", xen); - result.put("OpenVZ", openvz); - return result; - } - protected Injector injector() { return Guice.createInjector(new GleSYSParserModule(), new GsonModule()); } diff --git a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java index 80e19c035b..c0c89eb14a 100644 --- a/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java +++ b/sandbox-providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseServerDetailsTest.java @@ -49,10 +49,6 @@ public class ParseServerDetailsTest extends BaseItemParserTest { @SelectJson("server") @Consumes(MediaType.APPLICATION_JSON) public ServerDetails expected() { - return getData(); - } - - public static ServerDetails getData() { Cost cost = Cost.builder().amount(6.38).currency("EUR").timePeriod("month").build(); return ServerDetails.builder().id("vz1908384").hostname("jclouds-unit").cpuCores(1). memory(128).disk(5). From 6a838984068981dad3b23cca049aa183850eee18 Mon Sep 17 00:00:00 2001 From: Adam Lowe Date: Wed, 11 Jan 2012 01:07:16 +0000 Subject: [PATCH 05/82] Fixing bugs found by new ClientExpectTests --- .../src/main/java/org/jclouds/glesys/domain/ServerStatus.java | 2 +- .../src/main/java/org/jclouds/glesys/options/DomainOptions.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java index 9e802c34d9..8b8d01ceb0 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java @@ -150,7 +150,7 @@ public class ServerStatus { && Objects.equal(memory, other.memory) && Objects.equal(disk, other.disk) && Objects.equal(bandwidth, other.bandwidth) - && uptime == other.uptime; + && Objects.equal(uptime, other.uptime); } else { return false; } diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java index 0a322890f5..c2f6e80999 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java @@ -130,7 +130,7 @@ public class DomainOptions extends BaseHttpRequestOptions { * Configure the number of seconds a master or slave will wait before considering the data stale if it cannot reach the primary name server */ public DomainOptions expire(int expire) { - formParameters.put("primary_ns", Integer.toString(expire)); + formParameters.put("expire", Integer.toString(expire)); return this; } From 87cc6cc870c20c77cf256c5949c8e74cb151fa5a Mon Sep 17 00:00:00 2001 From: Adam Lowe Date: Wed, 11 Jan 2012 14:12:51 +0000 Subject: [PATCH 06/82] Adding class headers --- .../glesys/options/DomainAddOptions.java | 18 ++++++++++++++++++ .../options/DomainRecordEditOptions.java | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java index cba2b0b0c3..645b5977ae 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainAddOptions.java @@ -1,3 +1,21 @@ +/** + * 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.glesys.options; import org.jclouds.http.options.BaseHttpRequestOptions; diff --git a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java index f375375320..60b8cded8d 100644 --- a/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java +++ b/sandbox-providers/glesys/src/main/java/org/jclouds/glesys/options/DomainRecordEditOptions.java @@ -1,3 +1,21 @@ +/** + * 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.glesys.options; /** From 69f1fb5749e23aa9961afbc00c392faded31bc69 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Wed, 11 Jan 2012 01:47:20 -0500 Subject: [PATCH 07/82] Now using a cron job to enqueue 'store tweet' tasks every 5min since the GAE task queue actually removes tasks once they have completed successfully. This meant that the blobstores were only populated *once*. --- .../config/SpringServletConfig.java | 18 ++-- .../controller/EnqueueStoresController.java | 92 +++++++++++++++++++ .../src/main/platform/cron.xml | 28 ++++++ .../src/main/webapp/WEB-INF/queue.xml | 4 +- .../src/main/webapp/WEB-INF/web.xml | 17 +++- .../EnqueueStoresControllerTest.java | 65 +++++++++++++ 6 files changed, 213 insertions(+), 11 deletions(-) create mode 100644 demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java create mode 100644 demos/tweetstore/gae-tweetstore-spring/src/main/platform/cron.xml create mode 100644 demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java index 4d9e5d5606..53189d47b3 100644 --- a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java @@ -18,7 +18,6 @@ */ package org.jclouds.demo.tweetstore.config; -import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Predicates.in; @@ -47,6 +46,7 @@ import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.demo.tweetstore.config.util.CredentialsCollector; import org.jclouds.demo.tweetstore.controller.AddTweetsController; +import org.jclouds.demo.tweetstore.controller.EnqueueStoresController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses; import org.jclouds.gae.config.GoogleAppEngineConfigurationModule; @@ -65,7 +65,6 @@ import twitter4j.conf.ConfigurationBuilder; import com.google.appengine.api.taskqueue.Queue; import com.google.appengine.api.taskqueue.QueueFactory; -import com.google.appengine.api.taskqueue.TaskOptions.Method; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; @@ -121,10 +120,7 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA // get a queue for submitting store tweet requests queue = QueueFactory.getQueue("twitter"); - // submit a job to store tweets for each configured blobstore - for (String name : providerTypeToBlobStoreMap.keySet()) { - queue.add(withUrl("/store/do").header("context", name).method(Method.GET)); - } + logger.trace("Members initialized. Twitter: '%s', container: '%s', provider types: '%s'", twitterClient, container, providerTypeToBlobStoreMap.keySet()); } @@ -169,6 +165,11 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA return controller; } + @Bean + public EnqueueStoresController enqueueStoresController() { + return new EnqueueStoresController(providerTypeToBlobStoreMap, queue); + } + private void injectServletConfig(Servlet servlet) { logger.trace("About to inject servlet config '%s'", servletConfig); try { @@ -190,10 +191,11 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA Map urlMap = Maps.newHashMapWithExpectedSize(2); urlMap.put("/store/*", storeTweetsController()); urlMap.put("/tweets/*", addTweetsController()); + urlMap.put("/stores/*", enqueueStoresController()); mapping.setUrlMap(urlMap); /* - * "/store" and "/tweets" are part of the servlet mapping and thus stripped by the mapping if - * using default settings. + * "/store", "/tweets" and "/stores" are part of the servlet mapping and thus + * stripped by the mapping if using default settings. */ mapping.setAlwaysUseFullPath(true); return mapping; diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java new file mode 100644 index 0000000000..94568e4dec --- /dev/null +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java @@ -0,0 +1,92 @@ +/** + * 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.demo.tweetstore.controller; + +import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl; +import static com.google.appengine.repackaged.com.google.common.base.Strings.nullToEmpty; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.logging.Logger; + +import com.google.appengine.api.taskqueue.Queue; +import com.google.appengine.api.taskqueue.TaskOptions.Method; +import com.google.common.annotations.VisibleForTesting; + +/** + * Adds tasks to retrieve and store tweets in all registered contexts to an async + * task queue. + * + * @author Andrew Phillips + * @see StoreTweetsController + */ +@Singleton +public class EnqueueStoresController extends HttpServlet { + /** The serialVersionUID */ + private static final long serialVersionUID = 7215420527854203714L; + + private final Set contextNames; + private final Queue taskQueue; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + public EnqueueStoresController(Map contexts, + Queue taskQueue) { + contextNames = contexts.keySet(); + this.taskQueue = taskQueue; + } + + @VisibleForTesting + void enqueueStoreTweetTasks() { + for (String contextName : contextNames) { + logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName); + taskQueue.add(withUrl("/store/do").header("context", contextName).method(Method.GET)); + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + if (!nullToEmpty(request.getHeader("X-AppEngine-Cron")).equals("true")) { + response.sendError(401); + } + + try { + enqueueStoreTweetTasks(); + response.setContentType(MediaType.TEXT_PLAIN); + response.getWriter().println("Done!"); + } catch (Exception e) { + logger.error(e, "Error storing tweets"); + throw new ServletException(e); + } + } +} \ No newline at end of file diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/platform/cron.xml b/demos/tweetstore/gae-tweetstore-spring/src/main/platform/cron.xml new file mode 100644 index 0000000000..193a5402f6 --- /dev/null +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/platform/cron.xml @@ -0,0 +1,28 @@ + + + + + /stores/do + Enqueue 'store tweet' tasks for all contexts + every 10 minutes + + \ No newline at end of file diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml index e8c42d708a..1bc53f398d 100644 --- a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/queue.xml @@ -22,6 +22,8 @@ twitter - 1/m + + 2/m + 1 diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml index c6dead1056..971ada29cd 100644 --- a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml @@ -41,9 +41,22 @@ dispatcher /tweets/* - + + dispatcher + /stores/* + + + + + + /stores/* + + + admin + + + index.jsp - \ No newline at end of file diff --git a/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java new file mode 100644 index 0000000000..9a6ca29b32 --- /dev/null +++ b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java @@ -0,0 +1,65 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.demo.tweetstore.controller; + +import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl; +import static org.easymock.EasyMock.expect; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; + +import java.util.Map; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.testng.annotations.Test; + +import com.google.appengine.api.taskqueue.Queue; +import com.google.appengine.api.taskqueue.TaskOptions.Method; +import com.google.common.collect.ImmutableMap; + +/** + * Tests behavior of {@code StoreTweetsController} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class EnqueueStoresControllerTest { + + Map createBlobStores() { + Map contexts = ImmutableMap.of( + "test1", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"), + "test2", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy")); + return contexts; + } + + public void testEnqueueStores() { + Map stores = createBlobStores(); + Queue taskQueue = createMock(Queue.class); + EnqueueStoresController function = new EnqueueStoresController(stores, taskQueue); + + expect(taskQueue.add(withUrl("/store/do").header("context", "test1").method(Method.GET))).andReturn(null); + expect(taskQueue.add(withUrl("/store/do").header("context", "test2").method(Method.GET))).andReturn(null); + replay(taskQueue); + + function.enqueueStoreTweetTasks(); + + verify(taskQueue); + } +} From bf1311be9bcf7e73213f2b52f2e7b4102a61ceca Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Wed, 11 Jan 2012 14:10:17 -0500 Subject: [PATCH 08/82] Update gae-tweetstore to store tweets repeatedly too --- .../tweetstore/config/GuiceServletConfig.java | 9 +- .../controller/EnqueueStoresController.java | 92 +++++++++++++++++++ .../gae-tweetstore/src/main/platform/cron.xml | 28 ++++++ .../src/main/webapp/WEB-INF/queue.xml | 4 +- .../src/main/webapp/WEB-INF/web.xml | 12 ++- .../EnqueueStoresControllerTest.java | 65 +++++++++++++ 6 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java create mode 100644 demos/tweetstore/gae-tweetstore/src/main/platform/cron.xml create mode 100644 demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java diff --git a/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java index 19a444b145..e321c91414 100644 --- a/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java +++ b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/config/GuiceServletConfig.java @@ -18,7 +18,6 @@ */ package org.jclouds.demo.tweetstore.config; -import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Predicates.in; @@ -43,6 +42,7 @@ import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.demo.tweetstore.config.util.CredentialsCollector; import org.jclouds.demo.tweetstore.controller.AddTweetsController; +import org.jclouds.demo.tweetstore.controller.EnqueueStoresController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.gae.config.GoogleAppEngineConfigurationModule; @@ -53,7 +53,6 @@ import twitter4j.conf.ConfigurationBuilder; import com.google.appengine.api.taskqueue.Queue; import com.google.appengine.api.taskqueue.QueueFactory; -import com.google.appengine.api.taskqueue.TaskOptions.Method; import com.google.appengine.repackaged.com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; @@ -112,10 +111,6 @@ public class GuiceServletConfig extends GuiceServletContextListener { // get a queue for submitting store tweet requests queue = QueueFactory.getQueue("twitter"); - // submit a job to store tweets for each configured blobstore - for (String name : providerTypeToBlobStoreMap.keySet()) { - queue.add(withUrl("/store/do").header("context", name).method(Method.GET)); - } super.contextInitialized(servletContextEvent); } @@ -151,9 +146,11 @@ public class GuiceServletConfig extends GuiceServletContextListener { bind(new TypeLiteral>() { }).toInstance(providerTypeToBlobStoreMap); bind(Twitter.class).toInstance(twitterClient); + bind(Queue.class).toInstance(queue); bindConstant().annotatedWith(Names.named(PROPERTY_TWEETSTORE_CONTAINER)).to(container); serve("/store/*").with(StoreTweetsController.class); serve("/tweets/*").with(AddTweetsController.class); + serve("/stores/*").with(EnqueueStoresController.class); } }); } diff --git a/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java new file mode 100644 index 0000000000..94568e4dec --- /dev/null +++ b/demos/tweetstore/gae-tweetstore/src/main/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresController.java @@ -0,0 +1,92 @@ +/** + * 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.demo.tweetstore.controller; + +import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl; +import static com.google.appengine.repackaged.com.google.common.base.Strings.nullToEmpty; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.logging.Logger; + +import com.google.appengine.api.taskqueue.Queue; +import com.google.appengine.api.taskqueue.TaskOptions.Method; +import com.google.common.annotations.VisibleForTesting; + +/** + * Adds tasks to retrieve and store tweets in all registered contexts to an async + * task queue. + * + * @author Andrew Phillips + * @see StoreTweetsController + */ +@Singleton +public class EnqueueStoresController extends HttpServlet { + /** The serialVersionUID */ + private static final long serialVersionUID = 7215420527854203714L; + + private final Set contextNames; + private final Queue taskQueue; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + public EnqueueStoresController(Map contexts, + Queue taskQueue) { + contextNames = contexts.keySet(); + this.taskQueue = taskQueue; + } + + @VisibleForTesting + void enqueueStoreTweetTasks() { + for (String contextName : contextNames) { + logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName); + taskQueue.add(withUrl("/store/do").header("context", contextName).method(Method.GET)); + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + if (!nullToEmpty(request.getHeader("X-AppEngine-Cron")).equals("true")) { + response.sendError(401); + } + + try { + enqueueStoreTweetTasks(); + response.setContentType(MediaType.TEXT_PLAIN); + response.getWriter().println("Done!"); + } catch (Exception e) { + logger.error(e, "Error storing tweets"); + throw new ServletException(e); + } + } +} \ No newline at end of file diff --git a/demos/tweetstore/gae-tweetstore/src/main/platform/cron.xml b/demos/tweetstore/gae-tweetstore/src/main/platform/cron.xml new file mode 100644 index 0000000000..193a5402f6 --- /dev/null +++ b/demos/tweetstore/gae-tweetstore/src/main/platform/cron.xml @@ -0,0 +1,28 @@ + + + + + /stores/do + Enqueue 'store tweet' tasks for all contexts + every 10 minutes + + \ No newline at end of file diff --git a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml index e8c42d708a..1bc53f398d 100644 --- a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml +++ b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/queue.xml @@ -22,6 +22,8 @@ twitter - 1/m + + 2/m + 1 diff --git a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml index 11c41f1133..d5b17d7512 100644 --- a/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml +++ b/demos/tweetstore/gae-tweetstore/src/main/webapp/WEB-INF/web.xml @@ -39,7 +39,17 @@ org.jclouds.demo.tweetstore.config.GuiceServletConfig - + + + + + /stores/* + + + admin + + + index.jsp diff --git a/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java b/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java new file mode 100644 index 0000000000..9a6ca29b32 --- /dev/null +++ b/demos/tweetstore/gae-tweetstore/src/test/java/org/jclouds/demo/tweetstore/controller/EnqueueStoresControllerTest.java @@ -0,0 +1,65 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.demo.tweetstore.controller; + +import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl; +import static org.easymock.EasyMock.expect; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; + +import java.util.Map; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; +import org.testng.annotations.Test; + +import com.google.appengine.api.taskqueue.Queue; +import com.google.appengine.api.taskqueue.TaskOptions.Method; +import com.google.common.collect.ImmutableMap; + +/** + * Tests behavior of {@code StoreTweetsController} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class EnqueueStoresControllerTest { + + Map createBlobStores() { + Map contexts = ImmutableMap.of( + "test1", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"), + "test2", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy")); + return contexts; + } + + public void testEnqueueStores() { + Map stores = createBlobStores(); + Queue taskQueue = createMock(Queue.class); + EnqueueStoresController function = new EnqueueStoresController(stores, taskQueue); + + expect(taskQueue.add(withUrl("/store/do").header("context", "test1").method(Method.GET))).andReturn(null); + expect(taskQueue.add(withUrl("/store/do").header("context", "test2").method(Method.GET))).andReturn(null); + replay(taskQueue); + + function.enqueueStoreTweetTasks(); + + verify(taskQueue); + } +} From f90a2bd039ea453859406ceddcadb3e4d0324c5f Mon Sep 17 00:00:00 2001 From: andreisavu Date: Wed, 11 Jan 2012 22:18:28 +0200 Subject: [PATCH 09/82] Issue 681. Enhance jcloud to support aws-s3 Reduce Redundancy Storage (RRS) --- .../s3/blobstore/S3AsyncBlobStore.java | 12 +-- .../org/jclouds/s3/blobstore/S3BlobStore.java | 24 +++--- .../functions/BlobToObjectMetadata.java | 2 + .../org/jclouds/s3/domain/ObjectMetadata.java | 10 ++- .../jclouds/s3/options/PutObjectOptions.java | 1 + .../jclouds/blobstore/options/PutOptions.java | 4 +- .../org/jclouds/aws/s3/AWSS3AsyncClient.java | 5 ++ .../java/org/jclouds/aws/s3/AWSS3Client.java | 27 ++++--- .../aws/s3/blobstore/AWSS3AsyncBlobStore.java | 46 ++++++++++- .../aws/s3/blobstore/AWSS3BlobStore.java | 49 ++++++++++-- .../config/AWSS3BlobStoreContextModule.java | 1 + .../options/AWSS3PutObjectOptions.java | 71 ++++++++++++++++ .../s3/blobstore/options/AWSS3PutOptions.java | 80 +++++++++++++++++++ .../AsyncMultipartUploadStrategy.java | 3 +- .../strategy/MultipartUploadStrategy.java | 3 +- .../ParallelMultipartUploadStrategy.java | 5 +- .../SequentialMultipartUploadStrategy.java | 5 +- .../jclouds/aws/s3/AWSS3ClientLiveTest.java | 31 +++++++ ...SequentialMultipartUploadStrategyTest.java | 5 +- 19 files changed, 334 insertions(+), 50 deletions(-) create mode 100644 providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutObjectOptions.java create mode 100644 providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutOptions.java diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java index 28121c3f5f..7f2a5b6053 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java +++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3AsyncBlobStore.java @@ -232,6 +232,12 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore { */ @Override public ListenableFuture putBlob(String container, Blob blob) { + return putBlob(container, blob, PutOptions.NONE); + } + + @Override + public ListenableFuture putBlob(String container, Blob blob, PutOptions overrides) { + // TODO: Make use of options overrides PutObjectOptions options = new PutObjectOptions(); try { AccessControlList acl = bucketAcls.getUnchecked(container); @@ -256,12 +262,6 @@ public class S3AsyncBlobStore extends BaseAsyncBlobStore { return async.deleteObject(container, key); } - @Override - public ListenableFuture putBlob(String container, Blob blob, PutOptions options) { - // TODO implement options - return putBlob(container, blob); - } - @Override public ListenableFuture createContainerInLocation(Location location, String container, CreateContainerOptions options) { diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java index b8e16a00d5..6f8d01a925 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java +++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java @@ -232,15 +232,7 @@ public class S3BlobStore extends BaseBlobStore { */ @Override public String putBlob(String container, Blob blob) { - PutObjectOptions options = new PutObjectOptions(); - try { - AccessControlList acl = bucketAcls.getUnchecked(container); - if (acl != null && acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ)) - options.withAcl(CannedAccessPolicy.PUBLIC_READ); - } catch (CacheLoader.InvalidCacheLoadException e) { - // nulls not permitted from cache loader - } - return sync.putObject(container, blob2Object.apply(blob), options); + return putBlob(container, blob, PutOptions.NONE); } /** @@ -252,9 +244,17 @@ public class S3BlobStore extends BaseBlobStore { * object */ @Override - public String putBlob(String container, Blob blob, PutOptions options) { - // TODO implement options - return putBlob(container, blob); + public String putBlob(String container, Blob blob, PutOptions overrides) { + // TODO: Make use of options overrides + PutObjectOptions options = new PutObjectOptions(); + try { + AccessControlList acl = bucketAcls.getUnchecked(container); + if (acl != null && acl.hasPermission(GroupGranteeURI.ALL_USERS, Permission.READ)) + options.withAcl(CannedAccessPolicy.PUBLIC_READ); + } catch (CacheLoader.InvalidCacheLoadException e) { + // nulls not permitted from cache loader + } + return sync.putObject(container, blob2Object.apply(blob), options); } /** diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java index 9229e62a85..7bfdfeee2e 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java +++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/functions/BlobToObjectMetadata.java @@ -28,9 +28,11 @@ import org.jclouds.http.HttpUtils; import org.jclouds.rest.InvocationContext; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.s3.domain.MutableObjectMetadata; +import org.jclouds.s3.domain.ObjectMetadata; import org.jclouds.s3.domain.internal.MutableObjectMetadataImpl; import com.google.common.base.Function; +import org.jclouds.s3.reference.S3Headers; /** * @author Adrian Cole diff --git a/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java b/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java index ecefdc0800..b49cd16678 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java +++ b/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java @@ -38,7 +38,15 @@ import org.jclouds.io.ContentMetadata; public interface ObjectMetadata extends Comparable { public enum StorageClass { - STANDARD, REDUCED_REDUNDANCY + STANDARD, REDUCED_REDUNDANCY, UNKNOWN; + + public static StorageClass fromValue(String value) { + try { + return valueOf(value); + } catch(IllegalArgumentException e) { + return UNKNOWN; + } + } } /** diff --git a/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java b/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java index ffdb53e7fa..ddc6d7b016 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java +++ b/apis/s3/src/main/java/org/jclouds/s3/options/PutObjectOptions.java @@ -34,6 +34,7 @@ import org.jclouds.s3.domain.CannedAccessPolicy; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; +import org.jclouds.s3.domain.ObjectMetadata; /** * Contains options supported in the REST API for the PUT object operation. diff --git a/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java b/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java index 20c537327c..70adcb777a 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/options/PutOptions.java @@ -34,12 +34,12 @@ public class PutOptions implements Cloneable { public static final ImmutablePutOptions NONE = new ImmutablePutOptions(new PutOptions()); - private boolean multipart; + private boolean multipart = false; public PutOptions() { } - PutOptions(boolean multipart) { + public PutOptions(boolean multipart) { this.multipart = multipart; } diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java index 53669f993b..fc193341b7 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3AsyncClient.java @@ -22,6 +22,7 @@ import static org.jclouds.blobstore.attr.BlobScopes.CONTAINER; import java.util.Map; +import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions; import org.jclouds.javax.annotation.Nullable; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -54,9 +55,12 @@ import org.jclouds.s3.Bucket; import org.jclouds.s3.S3AsyncClient; import org.jclouds.s3.S3Client; import org.jclouds.s3.binders.BindAsHostPrefixIfConfigured; +import org.jclouds.s3.binders.BindS3ObjectMetadataToRequest; import org.jclouds.s3.domain.ObjectMetadata; +import org.jclouds.s3.domain.S3Object; import org.jclouds.s3.filters.RequestAuthorizeSignature; import org.jclouds.s3.functions.BindRegionToXmlPayload; +import org.jclouds.s3.functions.ObjectKey; import org.jclouds.s3.functions.ReturnFalseIfBucketAlreadyOwnedByYouOrIllegalState; import org.jclouds.s3.options.PutBucketOptions; import org.jclouds.s3.options.PutObjectOptions; @@ -74,6 +78,7 @@ import com.google.common.util.concurrent.ListenableFuture; @RequestFilters(RequestAuthorizeSignature.class) @BlobScope(CONTAINER) public interface AWSS3AsyncClient extends S3AsyncClient { + /** * @see S3Client#putBucketInRegion */ diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java index 5ed08d99e2..11decd9f61 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/AWSS3Client.java @@ -21,30 +21,33 @@ package org.jclouds.aws.s3; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions; import org.jclouds.concurrent.Timeout; import org.jclouds.io.Payload; import org.jclouds.s3.S3Client; import org.jclouds.s3.domain.ObjectMetadata; +import org.jclouds.s3.domain.S3Object; import org.jclouds.s3.options.PutObjectOptions; /** * Provides access to amazon-specific S3 features - * + * * @author Adrian Cole * @see AWSS3AsyncClient */ @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS) public interface AWSS3Client extends S3Client { + /** * This operation initiates a multipart upload and returns an upload ID. This upload ID is used * to associate all the parts in the specific multipart upload. You specify this upload ID in * each of your subsequent upload part requests (see Upload Part). You also include this upload * ID in the final request to either complete or abort the multipart upload request. - * + * *

Note

If you create an object using the multipart upload APIs, currently you cannot * copy the object between regions. - * - * + * + * * @param bucketName * namespace of the object you are to upload * @param objectMetadata @@ -61,8 +64,8 @@ public interface AWSS3Client extends S3Client { * parts will be freed. However, if any part uploads are currently in progress, those part * uploads might or might not succeed. As a result, it might be necessary to abort a given * multipart upload multiple times in order to completely free all storage consumed by all parts. - * - * + * + * * @param bucketName * namespace of the object you are deleting * @param key @@ -77,20 +80,20 @@ public interface AWSS3Client extends S3Client { * Initiate Multipart Upload) before you can upload any part. In response to your initiate * request. Amazon S3 returns an upload ID, a unique identifier, that you must include in your * upload part request. - * + * *

* Part numbers can be any number from 1 to 10,000, inclusive. A part number uniquely identifies * a part and also defines its position within the object being created. If you upload a new part * using the same part number that was used with a previous part, the previously uploaded part is * overwritten. Each part must be at least 5 MB in size, except the last part. There is no size * limit on the last part of your multipart upload. - * + * *

* To ensure that data is not corrupted when traversing the network, specify the Content-MD5 * header in the upload part request. Amazon S3 checks the part data against the provided MD5 * value. If they do not match, Amazon S3 returns an error. - * - * + * + * * @param bucketName * namespace of the object you are storing * @param key @@ -109,7 +112,7 @@ public interface AWSS3Client extends S3Client { String uploadPart(String bucketName, String key, int partNumber, String uploadId, Payload part); /** - * + * This operation completes a multipart upload by assembling previously uploaded parts. *

* You first initiate the multipart upload and then upload all parts using the Upload Parts @@ -129,7 +132,7 @@ public interface AWSS3Client extends S3Client { *

* Note that if Complete Multipart Upload fails, applications should be prepared to retry the * failed requests. - * + * * @param bucketName * namespace of the object you are deleting * @param key diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java index 38848d65cd..02d72315cb 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3AsyncBlobStore.java @@ -25,9 +25,12 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; +import com.google.common.cache.CacheLoader; import org.jclouds.Constants; import org.jclouds.aws.s3.AWSS3AsyncClient; import org.jclouds.aws.s3.AWSS3Client; +import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions; +import org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions; import org.jclouds.aws.s3.blobstore.strategy.AsyncMultipartUploadStrategy; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.domain.Blob; @@ -37,6 +40,8 @@ import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.collect.Memoized; import org.jclouds.domain.Location; +import org.jclouds.s3.S3AsyncClient; +import org.jclouds.s3.S3Client; import org.jclouds.s3.blobstore.S3AsyncBlobStore; import org.jclouds.s3.blobstore.functions.BlobToObject; import org.jclouds.s3.blobstore.functions.BucketToResourceList; @@ -49,14 +54,20 @@ import org.jclouds.s3.domain.AccessControlList; import com.google.common.base.Supplier; import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.ListenableFuture; +import org.jclouds.s3.domain.CannedAccessPolicy; +import org.jclouds.s3.domain.ObjectMetadata; + +import static org.jclouds.s3.domain.ObjectMetadata.StorageClass.REDUCED_REDUNDANCY; /** - * - * @author Tibor Kiss + * + * @author Tibor Kiss, Andrei Savu */ public class AWSS3AsyncBlobStore extends S3AsyncBlobStore { private final Provider multipartUploadStrategy; + private final LoadingCache bucketAcls; + private final BlobToObject blob2Object; @Inject public AWSS3AsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils, @@ -71,12 +82,39 @@ public class AWSS3AsyncBlobStore extends S3AsyncBlobStore { container2BucketListOptions, bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object, object2BlobMd, fetchBlobMetadataProvider, bucketAcls); this.multipartUploadStrategy = multipartUploadStrategy; + this.bucketAcls = bucketAcls; + this.blob2Object = blob2Object; } @Override public ListenableFuture putBlob(String container, Blob blob, PutOptions options) { - // need to use a provider if the strategy object is stateful - return multipartUploadStrategy.get().execute(container, blob); + if (options.isMultipart()) { + // need to use a provider if the strategy object is stateful + return multipartUploadStrategy.get().execute(container, blob, options); + } else if (options instanceof AWSS3PutOptions && + ((AWSS3PutOptions) options).getStorageClass() == REDUCED_REDUNDANCY) { + return putBlobWithReducedRedundancy(container, blob); + + } else { + return super.putBlob(container, blob, options); + } + } + + private ListenableFuture putBlobWithReducedRedundancy(String container, Blob blob) { + AWSS3PutObjectOptions options = new AWSS3PutObjectOptions(); + try { + AccessControlList acl = bucketAcls.getUnchecked(container); + if (acl != null && acl.hasPermission(AccessControlList.GroupGranteeURI.ALL_USERS, + AccessControlList.Permission.READ)) { + options.withAcl(CannedAccessPolicy.PUBLIC_READ); + } + options.storageClass(ObjectMetadata.StorageClass.REDUCED_REDUNDANCY); + + } catch (CacheLoader.InvalidCacheLoadException e) { + // nulls not permitted from cache loader + } + return S3AsyncClient.class.cast(getContext().getProviderSpecificContext().getApi()) + .putObject(container, blob2Object.apply(blob), options); } } diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java index 8bb382d61b..f981c3c85a 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobStore.java @@ -23,7 +23,10 @@ import java.util.Set; import javax.inject.Inject; import javax.inject.Provider; +import com.google.common.cache.CacheLoader; import org.jclouds.aws.s3.AWSS3Client; +import org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions; +import org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions; import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.domain.Blob; @@ -33,6 +36,7 @@ import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata; import org.jclouds.blobstore.util.BlobUtils; import org.jclouds.collect.Memoized; import org.jclouds.domain.Location; +import org.jclouds.s3.S3Client; import org.jclouds.s3.blobstore.S3BlobStore; import org.jclouds.s3.blobstore.functions.BlobToObject; import org.jclouds.s3.blobstore.functions.BucketToResourceList; @@ -44,15 +48,22 @@ import org.jclouds.s3.domain.AccessControlList; import com.google.common.base.Supplier; import com.google.common.cache.LoadingCache; +import org.jclouds.s3.domain.CannedAccessPolicy; +import org.jclouds.s3.domain.ObjectMetadata; +import org.jclouds.s3.options.PutObjectOptions; + +import static org.jclouds.s3.domain.ObjectMetadata.StorageClass.REDUCED_REDUNDANCY; /** - * Proived AWS S3 specific extensions. - * - * @author Tibor Kiss + * Provide AWS S3 specific extensions. + * + * @author Tibor Kiss, Andrei Savu */ public class AWSS3BlobStore extends S3BlobStore { private final Provider multipartUploadStrategy; + private final LoadingCache bucketAcls; + private final BlobToObject blob2Object; @Inject AWSS3BlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier defaultLocation, @@ -66,11 +77,39 @@ public class AWSS3BlobStore extends S3BlobStore { bucket2ResourceList, object2Blob, blob2ObjectGetOptions, blob2Object, object2BlobMd, fetchBlobMetadataProvider, bucketAcls); this.multipartUploadStrategy = multipartUploadStrategy; + this.bucketAcls = bucketAcls; + this.blob2Object = blob2Object; } @Override public String putBlob(String container, Blob blob, PutOptions options) { - // need to use a provider if the strategy object is stateful - return multipartUploadStrategy.get().execute(container, blob); + if (options.isMultipart()) { + // need to use a provider if the strategy object is stateful + return multipartUploadStrategy.get().execute(container, blob, options); + + } else if ((options instanceof AWSS3PutOptions) && + (((AWSS3PutOptions) options).getStorageClass() == REDUCED_REDUNDANCY)) { + return putBlobWithReducedRedundancy(container, blob); + + } else { + return super.putBlob(container, blob, options); + } + } + + private String putBlobWithReducedRedundancy(String container, Blob blob) { + AWSS3PutObjectOptions options = new AWSS3PutObjectOptions(); + try { + AccessControlList acl = bucketAcls.getUnchecked(container); + if (acl != null && acl.hasPermission(AccessControlList.GroupGranteeURI.ALL_USERS, + AccessControlList.Permission.READ)) { + options.withAcl(CannedAccessPolicy.PUBLIC_READ); + } + options.storageClass(ObjectMetadata.StorageClass.REDUCED_REDUNDANCY); + + } catch (CacheLoader.InvalidCacheLoadException e) { + // nulls not permitted from cache loader + } + return S3Client.class.cast(getContext().getProviderSpecificContext().getApi()) + .putObject(container, blob2Object.apply(blob), options); } } diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java index 71c85e2eec..89db15892c 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java @@ -28,6 +28,7 @@ import org.jclouds.aws.s3.blobstore.strategy.internal.ParallelMultipartUploadStr import org.jclouds.aws.s3.blobstore.strategy.internal.SequentialMultipartUploadStrategy; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.internal.BlobStoreContextImpl; +import org.jclouds.blobstore.options.PutOptions; import org.jclouds.s3.blobstore.S3AsyncBlobStore; import org.jclouds.s3.blobstore.S3BlobStore; import org.jclouds.s3.blobstore.config.S3BlobStoreContextModule; diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutObjectOptions.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutObjectOptions.java new file mode 100644 index 0000000000..eadf938b5e --- /dev/null +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutObjectOptions.java @@ -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.aws.s3.blobstore.options; + +import org.jclouds.s3.domain.CannedAccessPolicy; +import org.jclouds.s3.domain.ObjectMetadata; +import org.jclouds.s3.options.PutObjectOptions; +import org.jclouds.s3.reference.S3Headers; + +/** + * Contains options supported in the AWS S3 REST API for the PUT object operation + * + * @see PutObjectOptions + * @author Andrei Savu + */ +public class AWSS3PutObjectOptions extends PutObjectOptions { + + public static class Builder { + + /** + * @see AWSS3PutObjectOptions#storageClass + */ + public static AWSS3PutObjectOptions storageClass(ObjectMetadata.StorageClass storageClass) { + AWSS3PutObjectOptions options = new AWSS3PutObjectOptions(); + return options.storageClass(storageClass); + } + + /** + * @see AWSS3PutObjectOptions#withAcl + */ + public static AWSS3PutObjectOptions withAcl(CannedAccessPolicy acl) { + AWSS3PutObjectOptions options = new AWSS3PutObjectOptions(); + return options.withAcl(acl); + } + } + + private ObjectMetadata.StorageClass storageClass = ObjectMetadata.StorageClass.STANDARD; + + public AWSS3PutObjectOptions storageClass(ObjectMetadata.StorageClass storageClass) { + this.storageClass = storageClass; + if (storageClass != ObjectMetadata.StorageClass.STANDARD) { + this.replaceHeader(S3Headers.STORAGE_CLASS, this.storageClass.toString()); + } + return this; + } + + public ObjectMetadata.StorageClass getStorageClass() { + return storageClass; + } + + @Override + public AWSS3PutObjectOptions withAcl(CannedAccessPolicy acl) { + return (AWSS3PutObjectOptions) super.withAcl(acl); + } +} diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutOptions.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutOptions.java new file mode 100644 index 0000000000..e67f4a1bf6 --- /dev/null +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/options/AWSS3PutOptions.java @@ -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.aws.s3.blobstore.options; + +import org.jclouds.blobstore.options.PutOptions; +import org.jclouds.s3.domain.ObjectMetadata; + +/** + * Contains AWS-S3 specific options supported in the put blob operation + * + * @author Andrei Savu + */ +public class AWSS3PutOptions extends PutOptions { + + public static class Builder { + + /** + * @see AWSS3PutOptions#multipart() + */ + public static AWSS3PutOptions multipart() { + AWSS3PutOptions options = new AWSS3PutOptions(); + return (AWSS3PutOptions) options.multipart(); + } + + /** + * @see AWSS3PutOptions#storageClass + */ + public static AWSS3PutOptions storageClass(ObjectMetadata.StorageClass storageClass) { + AWSS3PutOptions options = new AWSS3PutOptions(); + return options.storageClass(storageClass); + } + } + + private ObjectMetadata.StorageClass storageClass; + + public AWSS3PutOptions() { + storageClass = ObjectMetadata.StorageClass.STANDARD; + } + + public AWSS3PutOptions(boolean multipart, ObjectMetadata.StorageClass storageClass) { + super(multipart); + this.storageClass = storageClass; + } + + public AWSS3PutOptions storageClass(ObjectMetadata.StorageClass storageClass) { + this.storageClass = storageClass; + return this; + } + + public ObjectMetadata.StorageClass getStorageClass() { + return storageClass; + } + + @Override + public AWSS3PutOptions clone() { + return new AWSS3PutOptions(isMultipart(), storageClass); + } + + @Override + public String toString() { + return "[multipart=" + isMultipart() + + " storageClass=" + storageClass + "]"; + } +} diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java index ccb165e6e6..2d199a23f9 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/AsyncMultipartUploadStrategy.java @@ -23,6 +23,7 @@ import org.jclouds.blobstore.domain.Blob; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.ImplementedBy; +import org.jclouds.blobstore.options.PutOptions; /** * @see execute(String container, Blob blob); + ListenableFuture execute(String container, Blob blob, PutOptions options); } diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java index e3cf3dddea..0d60d19b78 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/MultipartUploadStrategy.java @@ -22,6 +22,7 @@ import org.jclouds.aws.s3.blobstore.strategy.internal.SequentialMultipartUploadS import org.jclouds.blobstore.domain.Blob; import com.google.inject.ImplementedBy; +import org.jclouds.blobstore.options.PutOptions; /** * @see execute(final String container, final Blob blob) { + public ListenableFuture execute(final String container, final Blob blob, final PutOptions options) { return Futures.makeListenable( ioWorkerExecutor.submit(new Callable() { @Override @@ -240,7 +241,7 @@ public class ParallelMultipartUploadStrategy implements AsyncMultipartUploadStra throw rtex; } } else { - ListenableFuture futureETag = ablobstore.putBlob(container, blob); + ListenableFuture futureETag = ablobstore.putBlob(container, blob, options); return maxTime != null ? futureETag.get(maxTime,TimeUnit.SECONDS) : futureETag.get(); } diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java index 51078ae1b0..1198c23466 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java @@ -31,6 +31,7 @@ import org.jclouds.aws.s3.blobstore.AWSS3BlobStore; import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy; import org.jclouds.blobstore.KeyNotFoundException; import org.jclouds.blobstore.domain.Blob; +import org.jclouds.blobstore.options.PutOptions; import org.jclouds.blobstore.reference.BlobStoreConstants; import org.jclouds.io.Payload; import org.jclouds.io.PayloadSlicer; @@ -88,7 +89,7 @@ public class SequentialMultipartUploadStrategy implements MultipartUploadStrateg } @Override - public String execute(String container, Blob blob) { + public String execute(String container, Blob blob, PutOptions options) { String key = blob.getMetadata().getName(); Payload payload = blob.getPayload(); MultipartUploadSlicingAlgorithm algorithm = new MultipartUploadSlicingAlgorithm(); @@ -125,7 +126,7 @@ public class SequentialMultipartUploadStrategy implements MultipartUploadStrateg throw rtex; } } else { - return ablobstore.putBlob(container, blob); + return ablobstore.putBlob(container, blob, options); } } } diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java index e9361726c1..dd1769363c 100644 --- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java @@ -21,8 +21,10 @@ package org.jclouds.aws.s3; import static com.google.common.io.ByteStreams.join; import static com.google.common.io.ByteStreams.newInputStreamSupplier; import static com.google.common.io.ByteStreams.toByteArray; +import static org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions.Builder.storageClass; import static org.jclouds.crypto.CryptoStreams.md5; import static org.jclouds.io.Payloads.newByteArrayPayload; +import static org.jclouds.s3.domain.ObjectMetadata.StorageClass; import static org.testng.Assert.assertEquals; import java.io.ByteArrayInputStream; @@ -32,6 +34,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.zip.GZIPInputStream; +import org.jclouds.aws.s3.blobstore.AWSS3BlobStore; +import org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions; import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.KeyNotFoundException; import org.jclouds.blobstore.domain.Blob; @@ -39,7 +43,9 @@ import org.jclouds.blobstore.options.PutOptions; import org.jclouds.http.BaseJettyTest; import org.jclouds.http.apachehc.config.ApacheHCHttpCommandExecutorServiceModule; import org.jclouds.io.Payload; +import org.jclouds.s3.S3Client; import org.jclouds.s3.S3ClientLiveTest; +import org.jclouds.s3.domain.ObjectMetadata; import org.jclouds.s3.domain.ObjectMetadataBuilder; import org.jclouds.s3.domain.S3Object; import org.testng.ITestContext; @@ -154,6 +160,31 @@ public class AWSS3ClientLiveTest extends S3ClientLiveTest { Blob blob = blobStore.blobBuilder("const.txt") .payload(new File("target/const.txt")).build(); blobStore.putBlob(containerName, blob, PutOptions.Builder.multipart()); + + } finally { + returnContainer(containerName); + } + } + + public void testPutWithReducedRedundancyStorage() throws InterruptedException { + String containerName = getContainerName(); + try { + String blobName = "test-rrs"; + BlobStore blobStore = context.getBlobStore(); + blobStore.createContainerInLocation(null, containerName); + + Blob blob = blobStore.blobBuilder(blobName).payload("something").build(); + blobStore.putBlob(containerName, blob, + storageClass(StorageClass.REDUCED_REDUNDANCY)); + + S3Client s3Client = S3Client.class.cast(context.getProviderSpecificContext().getApi()); + S3Object s3Object = s3Client.getObject(containerName, blobName); + + /** + * This fails because the storage class is not part of the server response + */ + assertEquals(s3Object.getMetadata().getStorageClass(), StorageClass.REDUCED_REDUNDANCY); + } finally { returnContainer(containerName); } diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java index a3ddb05f8b..78a4cc6710 100644 --- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategyTest.java @@ -33,6 +33,7 @@ import org.jclouds.aws.s3.blobstore.AWSS3BlobStore; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.MutableBlobMetadata; +import org.jclouds.blobstore.options.PutOptions; import org.jclouds.io.MutableContentMetadata; import org.jclouds.io.Payload; import org.jclouds.io.PayloadSlicer; @@ -102,7 +103,7 @@ public class SequentialMultipartUploadStrategyTest { replay(ometa); SequentialMultipartUploadStrategy strategy = new SequentialMultipartUploadStrategy(ablobStore, slicer); - strategy.execute(container, blob); + strategy.execute(container, blob, PutOptions.NONE); verify(ablobStore); verify(slicer); @@ -167,7 +168,7 @@ public class SequentialMultipartUploadStrategyTest { SequentialMultipartUploadStrategy strategy = new SequentialMultipartUploadStrategy(ablobStore, slicer); try { - strategy.execute(container, blob); + strategy.execute(container, blob, PutOptions.NONE); fail("Should throw RuntimeException with TimeoutException cause!"); } catch (RuntimeException rtex) { TimeoutException timeout = Throwables2.getFirstThrowableOfType(rtex, TimeoutException.class); From 657c268db7eb4a2269965f25f2c3422762fa7e5e Mon Sep 17 00:00:00 2001 From: Aled Sage Date: Wed, 11 Jan 2012 20:42:25 +0000 Subject: [PATCH 10/82] Issue-572: added ListAllOptions for configuring BlobStores.listAll as eager --- .../org/jclouds/blobstore/BlobStores.java | 47 +++++++++- .../blobstore/options/ListAllOptions.java | 93 +++++++++++++++++++ .../org/jclouds/blobstore/BlobStoresTest.java | 54 ++++++++--- 3 files changed, 177 insertions(+), 17 deletions(-) create mode 100644 blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java diff --git a/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java b/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java index fb3b41840a..b59d60f44b 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/BlobStores.java @@ -22,22 +22,55 @@ import java.util.Iterator; import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.StorageMetadata; +import org.jclouds.blobstore.options.ListAllOptions; import org.jclouds.blobstore.options.ListContainerOptions; import com.google.common.annotations.Beta; import com.google.common.collect.AbstractIterator; +/** + * Utilities for using Blob Stores. + * + * @author Aled Sage + * @since 1.3 + */ public class BlobStores { + /** + * @see listAll(BlobStore, String, ListContainerOptions, ListAllOptions) + */ + @Beta + public static Iterable listAll(BlobStore blobStore, String container, + ListContainerOptions containerOptions) { + return listAll(blobStore, container, containerOptions, ListAllOptions.NONE); + } + /** * A variant of BlobStore.list(String, ListContainerOptions) that * produces an Iterable over the entire set of results, not just one * page, making multiple calls to BlobStore.list as needed. + * + * Note that if listAllOptions.isEager, then the first page will be fetched + * immediately and cached. Repeatedly iterating will not re-fetch (and thus + * will not refresh) the first page. + * + * @throws ContainerNotFoundException If listAllOptions.isEager and container cannot be found */ @Beta public static Iterable listAll(final BlobStore blobStore, final String container, - final ListContainerOptions options) { + final ListContainerOptions containerOptions, final ListAllOptions listAllOptions) { + final boolean eager = listAllOptions.isEager(); + final PageSet firstList; + final String firstMarker; + if (eager) { + firstList = blobStore.list(container, containerOptions); + firstMarker = firstList.getNextMarker(); + } else { + firstList = null; + firstMarker = null; + } + return new Iterable() { public Iterator iterator() { return new AbstractIterator() { @@ -47,10 +80,16 @@ public class BlobStores { public StorageMetadata computeNext() { while (true) { if (iterator == null) { - ListContainerOptions nextOptions = marker == null ? options : options.clone().afterMarker(marker); - PageSet list = blobStore.list(container, nextOptions); + PageSet list; + if (eager && marker == null) { + list = firstList; + marker = firstMarker; + } else { + ListContainerOptions nextOptions = marker == null ? containerOptions : containerOptions.clone().afterMarker(marker); + list = blobStore.list(container, nextOptions); + marker = list.getNextMarker(); + } iterator = list.iterator(); - marker = list.getNextMarker(); } if (iterator.hasNext()) { return iterator.next(); diff --git a/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java b/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java new file mode 100644 index 0000000000..4deb3d61cd --- /dev/null +++ b/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java @@ -0,0 +1,93 @@ +package org.jclouds.blobstore.options; + +import com.google.common.base.Objects; + +/** + * Contains options supported by BlobStores.listAll. + * + * @see ListOptions for recommended usage patterns + * + * @author Aled Sage + * @since 1.3 + */ +public class ListAllOptions implements Cloneable { + + public static final ImmutableListAllOptions NONE = new ImmutableListAllOptions(new ListAllOptions()); + + private boolean eager = false; + + public ListAllOptions() { + } + + ListAllOptions(boolean eagerness) { + this.eager = eagerness; + } + + public static class ImmutableListAllOptions extends ListAllOptions { + private final ListAllOptions delegate; + + public ImmutableListAllOptions(ListAllOptions delegate) { + this.delegate = delegate; + } + + @Override + public boolean isEager() { + return delegate.isEager(); + } + + @Override + public ListAllOptions eager(boolean val) { + throw new UnsupportedOperationException(); + } + } + + public boolean isEager() { + return eager; + } + + /** + * If eager, will connect to container immediately and fail-fast, rather than failing when + * first iterating over the list. + */ + public ListAllOptions eager(boolean val) { + this.eager = val; + return this; + } + + public static class Builder { + /** + * @see ListAllOptions#eager(boolean) + */ + public static ListAllOptions eager(boolean eager) { + ListAllOptions options = new ListAllOptions(); + return options.eager(eager); + } + } + + @Override + public ListAllOptions clone() { + return new ListAllOptions(isEager()); + } + + @Override + public String toString() { + return "[eager=" + eager + "]"; + } + + @Override + public int hashCode() { + return Objects.hashCode(eager); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ListAllOptions other = (ListAllOptions) obj; + return (eager == other.eager); + } +} diff --git a/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java b/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java index 9ea6d131b1..2e2c11f42d 100644 --- a/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java +++ b/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java @@ -29,6 +29,7 @@ import org.easymock.classextension.EasyMock; import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.internal.PageSetImpl; +import org.jclouds.blobstore.options.ListAllOptions; import org.jclouds.blobstore.options.ListContainerOptions; import org.testng.annotations.Test; @@ -41,15 +42,28 @@ public class BlobStoresTest { private final String containerName = "mycontainer"; + @Test(expectedExceptions={ContainerNotFoundException.class}) + public void testListAllForUnknownContainerFromTransientBlobStoreEagerly() throws Exception { + ListContainerOptions containerOptions = ListContainerOptions.NONE; + ListAllOptions listAllOptions = ListAllOptions.Builder.eager(true); + BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummyid", "dummykey"); + try { + BlobStore blobStore = context.getBlobStore(); + BlobStores.listAll(blobStore, "wrongcontainer", containerOptions, listAllOptions); + } finally { + context.close(); + } + } + + /** + * Default listAll is not eager, so test that exception is thrown when first attempt to iterate. + */ @Test(expectedExceptions={ContainerNotFoundException.class}) public void testListAllForUnknownContainerFromTransientBlobStore() throws Exception { ListContainerOptions options = ListContainerOptions.NONE; BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummyid", "dummykey"); try { BlobStore blobStore = context.getBlobStore(); - - // Arguably it would be best to throw the exception as soon as listAll is called; but because - // the iterator is lazy we don't the exception until we first call iterator().next() or hasNext(). Iterable iterable = BlobStores.listAll(blobStore, "wrongcontainer", options); iterable.iterator().hasNext(); } finally { @@ -59,8 +73,18 @@ public class BlobStoresTest { @Test public void testListAllFromTransientBlobStore() throws Exception { + runListAllFromTransientBlobStore(false); + } + + @Test + public void testListAllFromTransientBlobStoreEagerly() throws Exception { + runListAllFromTransientBlobStore(true); + } + + private void runListAllFromTransientBlobStore(boolean eager) throws Exception { + final int numTimesToIterate = 2; final int NUM_BLOBS = 31; - ListContainerOptions options = ListContainerOptions.Builder.maxResults(10); + ListContainerOptions containerOptions = ListContainerOptions.Builder.maxResults(10); BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummyid", "dummykey"); BlobStore blobStore = null; try { @@ -73,16 +97,20 @@ public class BlobStoresTest { expectedNames.add(blobName); } - Iterable iterable = BlobStores.listAll(blobStore, containerName, options); - Iterable iterableNames = Iterables.transform(iterable, new Function() { - @Override public String apply(StorageMetadata input) { - return input.getName(); - }}); + ListAllOptions listAllOptions = ListAllOptions.Builder.eager(eager); + Iterable iterable = BlobStores.listAll(blobStore, containerName, containerOptions, listAllOptions); - // Note that blob.getMetadata being put does not equal blob metadata being retrieved - // because uri is null in one and populated in the other. - // Therefore we just compare names to ensure the iterator worked. - assertEquals(ImmutableSet.copyOf(iterableNames), expectedNames); + for (int i = 0; i < numTimesToIterate; i++) { + Iterable iterableNames = Iterables.transform(iterable, new Function() { + @Override public String apply(StorageMetadata input) { + return input.getName(); + }}); + + // Note that blob.getMetadata being put does not equal blob metadata being retrieved + // because uri is null in one and populated in the other. + // Therefore we just compare names to ensure the iterator worked. + assertEquals(ImmutableSet.copyOf(iterableNames), expectedNames); + } } finally { if (blobStore != null) blobStore.deleteContainer(containerName); context.close(); From bf330f63488fe77e25affee98f197e171f252719 Mon Sep 17 00:00:00 2001 From: andreisavu Date: Wed, 11 Jan 2012 23:02:36 +0200 Subject: [PATCH 11/82] Use listBucket to query StorageClass for a blob --- .../java/org/jclouds/s3/domain/ObjectMetadata.java | 10 +--------- .../java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java | 11 ++++++----- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java b/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java index b49cd16678..ecefdc0800 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java +++ b/apis/s3/src/main/java/org/jclouds/s3/domain/ObjectMetadata.java @@ -38,15 +38,7 @@ import org.jclouds.io.ContentMetadata; public interface ObjectMetadata extends Comparable { public enum StorageClass { - STANDARD, REDUCED_REDUNDANCY, UNKNOWN; - - public static StorageClass fromValue(String value) { - try { - return valueOf(value); - } catch(IllegalArgumentException e) { - return UNKNOWN; - } - } + STANDARD, REDUCED_REDUNDANCY } /** diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java index dd1769363c..8f6908eea4 100644 --- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java @@ -25,6 +25,7 @@ import static org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions.Builder.stora import static org.jclouds.crypto.CryptoStreams.md5; import static org.jclouds.io.Payloads.newByteArrayPayload; import static org.jclouds.s3.domain.ObjectMetadata.StorageClass; +import static org.jclouds.s3.options.ListBucketOptions.Builder.withPrefix; import static org.testng.Assert.assertEquals; import java.io.ByteArrayInputStream; @@ -45,9 +46,11 @@ import org.jclouds.http.apachehc.config.ApacheHCHttpCommandExecutorServiceModule import org.jclouds.io.Payload; import org.jclouds.s3.S3Client; import org.jclouds.s3.S3ClientLiveTest; +import org.jclouds.s3.domain.ListBucketResponse; import org.jclouds.s3.domain.ObjectMetadata; import org.jclouds.s3.domain.ObjectMetadataBuilder; import org.jclouds.s3.domain.S3Object; +import org.jclouds.s3.options.ListBucketOptions; import org.testng.ITestContext; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -178,12 +181,10 @@ public class AWSS3ClientLiveTest extends S3ClientLiveTest { storageClass(StorageClass.REDUCED_REDUNDANCY)); S3Client s3Client = S3Client.class.cast(context.getProviderSpecificContext().getApi()); - S3Object s3Object = s3Client.getObject(containerName, blobName); + ListBucketResponse response = s3Client.listBucket(containerName, withPrefix(blobName)); - /** - * This fails because the storage class is not part of the server response - */ - assertEquals(s3Object.getMetadata().getStorageClass(), StorageClass.REDUCED_REDUNDANCY); + ObjectMetadata metadata = response.iterator().next(); + assertEquals(metadata.getStorageClass(), StorageClass.REDUCED_REDUNDANCY); } finally { returnContainer(containerName); From ce5244f8d5e437906719f8a87ba2abdcedad9c5a Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Wed, 11 Jan 2012 13:37:15 -0800 Subject: [PATCH 12/82] Issue 781:update to guava 11.0.1 --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index ebb06b6d8e..8bef999e5d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -109,7 +109,7 @@ com.google.guava guava - 11.0 + 11.0.1 From 21b8aadbfb7f5fcedf5d6ecc41ebc0f8e78cb5ff Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Wed, 11 Jan 2012 14:39:13 -0800 Subject: [PATCH 13/82] Issue 809:update to latest jersey and move off old repo --- core/pom.xml | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 8bef999e5d..a8aa286afa 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -38,21 +38,6 @@ http://jclouds.googlecode.com/svn/trunk - - - - - jersey - http://download.java.net/maven/2 - - true - - - false - - - - net.oauth.core @@ -74,7 +59,7 @@ com.sun.jersey jersey-core - 1.6 + 1.11 com.google.inject.extensions From d9cb5e2dc6324fd4f6d02e31655ac47e0a93c1dd Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Wed, 11 Jan 2012 14:58:02 -0800 Subject: [PATCH 14/82] Issue 810:update test dependencies (testng + easymock) --- project/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/pom.xml b/project/pom.xml index bf7f149394..2f5cde13c8 100644 --- a/project/pom.xml +++ b/project/pom.xml @@ -225,13 +225,13 @@ org.testng testng - 6.0.1 + 6.3.1 test org.easymock easymockclassextension - 2.4 + 3.1 test From 86929f91f6f16f8387ea924ce9d45518529078c9 Mon Sep 17 00:00:00 2001 From: Aled Sage Date: Thu, 12 Jan 2012 00:39:27 +0000 Subject: [PATCH 15/82] Issue-572: added @Beta to ListAllOptions --- .../main/java/org/jclouds/blobstore/options/ListAllOptions.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java b/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java index 4deb3d61cd..bdc4352d6f 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/options/ListAllOptions.java @@ -1,5 +1,6 @@ package org.jclouds.blobstore.options; +import com.google.common.annotations.Beta; import com.google.common.base.Objects; /** @@ -10,6 +11,7 @@ import com.google.common.base.Objects; * @author Aled Sage * @since 1.3 */ +@Beta public class ListAllOptions implements Cloneable { public static final ImmutableListAllOptions NONE = new ImmutableListAllOptions(new ListAllOptions()); From 2bff310db2f66ada7b2038bed9d44a5f11d4169f Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Wed, 11 Jan 2012 20:12:44 -0800 Subject: [PATCH 16/82] fixed thread safety in test --- .../org/jclouds/blobstore/BlobStoresTest.java | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java b/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java index 2e2c11f42d..0d8c8bd571 100644 --- a/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java +++ b/blobstore/src/test/java/org/jclouds/blobstore/BlobStoresTest.java @@ -18,14 +18,14 @@ */ package org.jclouds.blobstore; -import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.EasyMock.createMock; import static org.testng.Assert.assertEquals; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.easymock.classextension.EasyMock; +import org.easymock.EasyMock; import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.StorageMetadata; import org.jclouds.blobstore.domain.internal.PageSetImpl; @@ -38,11 +38,12 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +@Test(singleThreaded = true, testName = "BlobStoresTest") public class BlobStoresTest { private final String containerName = "mycontainer"; - @Test(expectedExceptions={ContainerNotFoundException.class}) + @Test(expectedExceptions = { ContainerNotFoundException.class }) public void testListAllForUnknownContainerFromTransientBlobStoreEagerly() throws Exception { ListContainerOptions containerOptions = ListContainerOptions.NONE; ListAllOptions listAllOptions = ListAllOptions.Builder.eager(true); @@ -58,7 +59,7 @@ public class BlobStoresTest { /** * Default listAll is not eager, so test that exception is thrown when first attempt to iterate. */ - @Test(expectedExceptions={ContainerNotFoundException.class}) + @Test(expectedExceptions = { ContainerNotFoundException.class }) public void testListAllForUnknownContainerFromTransientBlobStore() throws Exception { ListContainerOptions options = ListContainerOptions.NONE; BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummyid", "dummykey"); @@ -70,7 +71,7 @@ public class BlobStoresTest { context.close(); } } - + @Test public void testListAllFromTransientBlobStore() throws Exception { runListAllFromTransientBlobStore(false); @@ -89,48 +90,53 @@ public class BlobStoresTest { BlobStore blobStore = null; try { blobStore = context.getBlobStore(); - blobStore.createContainerInLocation(null, containerName); + blobStore.createContainerInLocation(null, containerName); Set expectedNames = new HashSet(); for (int i = 0; i < NUM_BLOBS; i++) { - String blobName = "myname"+i; - blobStore.putBlob(containerName, blobStore.blobBuilder(blobName).payload("payload"+i).build()); + String blobName = "myname" + i; + blobStore.putBlob(containerName, blobStore.blobBuilder(blobName).payload("payload" + i).build()); expectedNames.add(blobName); } - + ListAllOptions listAllOptions = ListAllOptions.Builder.eager(eager); - Iterable iterable = BlobStores.listAll(blobStore, containerName, containerOptions, listAllOptions); - + Iterable iterable = BlobStores.listAll(blobStore, containerName, containerOptions, + listAllOptions); + for (int i = 0; i < numTimesToIterate; i++) { - Iterable iterableNames = Iterables.transform(iterable, new Function() { - @Override public String apply(StorageMetadata input) { + Iterable iterableNames = Iterables.transform(iterable, new Function() { + @Override + public String apply(StorageMetadata input) { return input.getName(); - }}); - - // Note that blob.getMetadata being put does not equal blob metadata being retrieved + } + }); + + // Note that blob.getMetadata being put does not equal blob metadata being retrieved // because uri is null in one and populated in the other. // Therefore we just compare names to ensure the iterator worked. assertEquals(ImmutableSet.copyOf(iterableNames), expectedNames); } } finally { - if (blobStore != null) blobStore.deleteContainer(containerName); + if (blobStore != null) + blobStore.deleteContainer(containerName); context.close(); } } - + @Test public void testListAllWhenOnePage() throws Exception { BlobStore blobStore = createMock(BlobStore.class); ListContainerOptions options = ListContainerOptions.NONE; StorageMetadata v1 = createMock(StorageMetadata.class); PageSet pageSet = new PageSetImpl(Collections.singletonList(v1), null); - - EasyMock.>expect(blobStore.list(containerName, options)).andReturn(pageSet).once(); + + EasyMock.> expect(blobStore.list(containerName, options)).andReturn(pageSet) + .once(); EasyMock.replay(blobStore); - + Iterable iterable = BlobStores.listAll(blobStore, containerName, options); assertEquals(ImmutableList.copyOf(iterable), ImmutableList.of(v1)); } - + @Test public void testListAllWhenTwoPages() throws Exception { BlobStore blobStore = createMock(BlobStore.class); @@ -140,11 +146,13 @@ public class BlobStoresTest { StorageMetadata v2 = createMock(StorageMetadata.class); PageSet pageSet = new PageSetImpl(Collections.singletonList(v1), "marker1"); PageSet pageSet2 = new PageSetImpl(Collections.singletonList(v2), null); - - EasyMock.>expect(blobStore.list(containerName, options)).andReturn(pageSet).once(); - EasyMock.>expect(blobStore.list(containerName, options2)).andReturn(pageSet2).once(); + + EasyMock.> expect(blobStore.list(containerName, options)).andReturn(pageSet) + .once(); + EasyMock.> expect(blobStore.list(containerName, options2)).andReturn(pageSet2) + .once(); EasyMock.replay(blobStore); - + Iterable iterable = BlobStores.listAll(blobStore, containerName, options); assertEquals(ImmutableList.copyOf(iterable), ImmutableList.of(v1, v2)); } From a2afd265b89b61c7cef66e0c600e702c48c0b12d Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Wed, 11 Jan 2012 18:10:52 +0200 Subject: [PATCH 17/82] Regenerate Host.equals()/hashCode()/toString() as they were out of date --- .../org/jclouds/cloudstack/domain/Host.java | 137 ++++++++---------- 1 file changed, 60 insertions(+), 77 deletions(-) diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java index 8b59238963..3a01ca8437 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java @@ -707,6 +707,59 @@ public class Host implements Comparable { return zoneName; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Host host = (Host) o; + + if (averageLoad != host.averageLoad) return false; + if (clusterId != host.clusterId) return false; + if (cpuNumber != host.cpuNumber) return false; + if (cpuSpeed != host.cpuSpeed) return false; + if (Float.compare(host.cpuWithOverProvisioning, cpuWithOverProvisioning) != 0) return false; + if (diskSizeAllocated != host.diskSizeAllocated) return false; + if (diskSizeTotal != host.diskSizeTotal) return false; + if (hasEnoughCapacity != host.hasEnoughCapacity) return false; + if (id != host.id) return false; + if (jobId != host.jobId) return false; + if (localStorageActive != host.localStorageActive) return false; + if (managementServerId != host.managementServerId) return false; + if (memoryAllocated != host.memoryAllocated) return false; + if (memoryTotal != host.memoryTotal) return false; + if (memoryUsed != host.memoryUsed) return false; + if (networkKbsRead != host.networkKbsRead) return false; + if (networkKbsWrite != host.networkKbsWrite) return false; + if (osCategoryId != host.osCategoryId) return false; + if (osCategoryName != host.osCategoryName) return false; + if (podId != host.podId) return false; + if (zoneId != host.zoneId) return false; + if (allocationState != host.allocationState) return false; + if (capabilities != null ? !capabilities.equals(host.capabilities) : host.capabilities != null) return false; + if (clusterName != null ? !clusterName.equals(host.clusterName) : host.clusterName != null) return false; + if (clusterType != host.clusterType) return false; + if (cpuAllocated != null ? !cpuAllocated.equals(host.cpuAllocated) : host.cpuAllocated != null) return false; + if (cpuUsed != null ? !cpuUsed.equals(host.cpuUsed) : host.cpuUsed != null) return false; + if (created != null ? !created.equals(host.created) : host.created != null) return false; + if (disconnected != null ? !disconnected.equals(host.disconnected) : host.disconnected != null) return false; + if (events != null ? !events.equals(host.events) : host.events != null) return false; + if (hostTags != null ? !hostTags.equals(host.hostTags) : host.hostTags != null) return false; + if (hypervisor != null ? !hypervisor.equals(host.hypervisor) : host.hypervisor != null) return false; + if (ipAddress != null ? !ipAddress.equals(host.ipAddress) : host.ipAddress != null) return false; + if (jobStatus != host.jobStatus) return false; + if (lastPinged != null ? !lastPinged.equals(host.lastPinged) : host.lastPinged != null) return false; + if (name != null ? !name.equals(host.name) : host.name != null) return false; + if (podName != null ? !podName.equals(host.podName) : host.podName != null) return false; + if (removed != null ? !removed.equals(host.removed) : host.removed != null) return false; + if (state != host.state) return false; + if (type != host.type) return false; + if (version != null ? !version.equals(host.version) : host.version != null) return false; + if (zoneName != null ? !zoneName.equals(host.zoneName) : host.zoneName != null) return false; + + return true; + } + @Override public int hashCode() { int result = (int) (id ^ (id >>> 32)); @@ -720,7 +773,7 @@ public class Host implements Comparable { result = 31 * result + cpuNumber; result = 31 * result + cpuSpeed; result = 31 * result + (cpuUsed != null ? cpuUsed.hashCode() : 0); - result = 31 * result + (int) cpuWithOverProvisioning; + result = 31 * result + (cpuWithOverProvisioning != +0.0f ? Float.floatToIntBits(cpuWithOverProvisioning) : 0); result = 31 * result + (created != null ? created.hashCode() : 0); result = 31 * result + (disconnected != null ? disconnected.hashCode() : 0); result = 31 * result + (int) (diskSizeAllocated ^ (diskSizeAllocated >>> 32)); @@ -754,90 +807,20 @@ public class Host implements Comparable { return result; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Host host = (Host) o; - - if (averageLoad != host.averageLoad) return false; - if (clusterId != host.clusterId) return false; - if (cpuAllocated != host.cpuAllocated) return false; - if (cpuNumber != host.cpuNumber) return false; - if (cpuSpeed != host.cpuSpeed) return false; - if (cpuUsed != host.cpuUsed) return false; - if (cpuWithOverProvisioning != host.cpuWithOverProvisioning) return false; - if (disconnected != host.disconnected) return false; - if (diskSizeAllocated != host.diskSizeAllocated) return false; - if (diskSizeTotal != host.diskSizeTotal) return false; - if (hasEnoughCapacity != host.hasEnoughCapacity) return false; - if (id != host.id) return false; - if (localStorageActive != host.localStorageActive) return false; - if (jobId != host.jobId) return false; - if (managementServerId != host.managementServerId) return false; - if (memoryAllocated != host.memoryAllocated) return false; - if (memoryTotal != host.memoryTotal) return false; - if (memoryUsed != host.memoryUsed) return false; - if (networkKbsRead != host.networkKbsRead) return false; - if (networkKbsWrite != host.networkKbsWrite) return false; - if (osCategoryId != host.osCategoryId) return false; - if (osCategoryName != host.osCategoryName) return false; - if (podId != host.podId) return false; - if (zoneId != host.zoneId) return false; - if (allocationState != null ? !allocationState.equals(host.allocationState) : host.allocationState != null) - return false; - if (capabilities != null ? !capabilities.equals(host.capabilities) : host.capabilities != null) - return false; - if (clusterName != null ? !clusterName.equals(host.clusterName) : host.clusterName != null) - return false; - if (clusterType != null ? !clusterType.equals(host.clusterType) : host.clusterType != null) - return false; - if (created != null ? !created.equals(host.created) : host.created != null) - return false; - if (events != null ? !events.equals(host.events) : host.events != null) - return false; - if (hostTags != null ? !hostTags.equals(host.hostTags) : host.hostTags != null) - return false; - if (hypervisor != null ? !hypervisor.equals(host.hypervisor) : host.hypervisor != null) - return false; - if (ipAddress != null ? !ipAddress.equals(host.ipAddress) : host.ipAddress != null) - return false; - if (jobStatus != host.jobStatus) return false; - if (lastPinged != null ? !lastPinged.equals(host.lastPinged) : host.lastPinged != null) - return false; - if (name != null ? !name.equals(host.name) : host.name != null) - return false; - if (podName != null ? !podName.equals(host.podName) : host.podName != null) - return false; - if (removed != null ? !removed.equals(host.removed) : host.removed != null) - return false; - if (state != null ? !state.equals(host.state) : host.state != null) - return false; - if (type != null ? !type.equals(host.type) : host.type != null) - return false; - if (version != null ? !version.equals(host.version) : host.version != null) - return false; - if (zoneName != null ? !zoneName.equals(host.zoneName) : host.zoneName != null) - return false; - - return true; - } - @Override public String toString() { return "Host{" + "id=" + id + - ", allocationState='" + allocationState + '\'' + + ", allocationState=" + allocationState + ", averageLoad=" + averageLoad + ", capabilities='" + capabilities + '\'' + ", clusterId=" + clusterId + ", clusterName='" + clusterName + '\'' + - ", clusterType='" + clusterType + '\'' + - ", cpuAllocated=" + cpuAllocated + + ", clusterType=" + clusterType + + ", cpuAllocated='" + cpuAllocated + '\'' + ", cpuNumber=" + cpuNumber + ", cpuSpeed=" + cpuSpeed + - ", cpuUsed=" + cpuUsed + + ", cpuUsed='" + cpuUsed + '\'' + ", cpuWithOverProvisioning=" + cpuWithOverProvisioning + ", created=" + created + ", disconnected=" + disconnected + @@ -864,8 +847,8 @@ public class Host implements Comparable { ", podId=" + podId + ", podName='" + podName + '\'' + ", removed=" + removed + - ", state='" + state + '\'' + - ", type='" + type + '\'' + + ", state=" + state + + ", type=" + type + ", version='" + version + '\'' + ", zoneId=" + zoneId + ", zoneName='" + zoneName + '\'' + From 7833ca557b90d43176301341bc64dbb803250843 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Wed, 11 Jan 2012 18:11:35 +0200 Subject: [PATCH 18/82] Add expect-style test for GlobalHostClient.listHosts() --- .../features/GlobalHostClientExpectTest.java | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java new file mode 100644 index 0000000000..55b2a7108b --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -0,0 +1,112 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.features; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.CloudStackContext; +import org.jclouds.cloudstack.domain.ConfigurationEntry; +import org.jclouds.cloudstack.domain.Host; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.Calendar; +import java.util.Date; +import java.util.Set; +import java.util.TimeZone; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +/** + * Test the CloudStack GlobalHostClient + * + * @author Richard Downer + */ +@Test(groups = "unit", testName = "GlobalConfigurationClientExpectTest") +public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTest { + + @Test + public void testListHostsWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listHosts&apiKey=identity&signature=wsv4UBgXxURW0pNlso4MT9E052s%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/listhostsresponse.json")) + .statusCode(200).build(); + + Set actual = requestSendsResponse(request, response).listHosts(); + + Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC"); + Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "UTC"); + Host host1 = Host.builder().id(1).name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId(223098941760041L).clusterId(1).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build(); + + Date disconnected = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC"); + lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 42, 30, "UTC"); + created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC"); + Host host2 = Host.builder().id(2).name("nfs://10.26.26.165/mnt/nfs/cs_sec").state(Host.State.ALERT).disconnected(disconnected).type(Host.Type.SECONDARY_STORAGE).ipAddress("nfs").zoneId(1).zoneName("Dev Zone 1").version("2.2.12.20110928142833").hypervisor("None").lastPinged(lastPinged).localStorageActive(false).created(created).events("ManagementServerDown; AgentDisconnected; Remove; MaintenanceRequested; AgentConnected; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build(); + + lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC"); + created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 35, 51, "UTC"); + Host host3 = Host.builder().id(3).name("s-1-VM").state(Host.State.UP).type(Host.Type.SECONDARY_STORAGE_VM).ipAddress("10.26.26.81").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").lastPinged(lastPinged).managementServerId(223098941760041L).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build(); + + lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC"); + created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 36, 46, "UTC"); + Host host4 = Host.builder().id(4).name("v-2-VM").state(Host.State.UP).type(Host.Type.CONSOLE_PROXY).ipAddress("10.26.26.96").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").lastPinged(lastPinged).managementServerId(223098941760041L).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build(); + + Set expected = ImmutableSet.of(host1, host2, host3, host4); + + assertEquals(actual, expected); + } + + private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName)); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, month); + cal.set(Calendar.DATE, date); + cal.set(Calendar.HOUR_OF_DAY, hour); + cal.set(Calendar.MINUTE, minute); + cal.set(Calendar.SECOND, second); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + @Test + public void testListHostsEmptyOn404() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listHosts&apiKey=identity&signature=wsv4UBgXxURW0pNlso4MT9E052s%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder().statusCode(404).build(); + GlobalHostClient client = requestSendsResponse(request, response); + + assertEquals(client.listHosts(), ImmutableSet.of()); + } + + @Override + protected GlobalHostClient clientFrom(CloudStackContext context) { + return context.getGlobalContext().getApi().getHostClient(); + } +} \ No newline at end of file From d4293bdb7a3bf81f927b524f604bdb7341ea0a38 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 11:24:04 +0200 Subject: [PATCH 19/82] Add expect-style test for GlobalHostClient.listClusters() --- .../features/GlobalHostClientExpectTest.java | 58 +++++++++++++++---- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 55b2a7108b..89ac050f04 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -22,6 +22,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import org.jclouds.cloudstack.CloudStackContext; +import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.ConfigurationEntry; import org.jclouds.cloudstack.domain.Host; import org.jclouds.http.HttpRequest; @@ -80,18 +81,6 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, expected); } - private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) { - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName)); - cal.set(Calendar.YEAR, year); - cal.set(Calendar.MONTH, month); - cal.set(Calendar.DATE, date); - cal.set(Calendar.HOUR_OF_DAY, hour); - cal.set(Calendar.MINUTE, minute); - cal.set(Calendar.SECOND, second); - cal.set(Calendar.MILLISECOND, 0); - return cal.getTime(); - } - @Test public void testListHostsEmptyOn404() { HttpRequest request = HttpRequest.builder() @@ -105,6 +94,51 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(client.listHosts(), ImmutableSet.of()); } + @Test + public void testListClustersWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listClusters&apiKey=identity&signature=MWOOe7bm1J14DIfLjAGqsSVb8oo%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/listclustersresponse.json")) + .statusCode(200).build(); + + Set actual = requestSendsResponse(request, response).listClusters(); + + Cluster cluster1 = Cluster.builder().id(1).name("Xen Clust 1").podId(1).podName("Dev Pod 1").zoneId(1).zoneName("Dev Zone 1").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build(); + Cluster cluster2 = Cluster.builder().id(2).name("Xen Clust 1").podId(2).podName("Dev Pod 2").zoneId(2).zoneName("Dev Zone 2").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build(); + ImmutableSet expected = ImmutableSet.of(cluster1, cluster2); + + assertEquals(actual, expected); + } + + @Test + public void testListClustersEmptyOn404() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=listClusters&apiKey=identity&signature=MWOOe7bm1J14DIfLjAGqsSVb8oo%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder().statusCode(404).build(); + GlobalHostClient client = requestSendsResponse(request, response); + + assertEquals(client.listClusters(), ImmutableSet.of()); + } + + private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName)); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, month); + cal.set(Calendar.DATE, date); + cal.set(Calendar.HOUR_OF_DAY, hour); + cal.set(Calendar.MINUTE, minute); + cal.set(Calendar.SECOND, second); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + @Override protected GlobalHostClient clientFrom(CloudStackContext context) { return context.getGlobalContext().getApi().getHostClient(); From 03a5a55fccad827dac211d2b215ce81183afda47 Mon Sep 17 00:00:00 2001 From: Christophe Hamerling Date: Thu, 12 Jan 2012 11:40:27 +0100 Subject: [PATCH 20/82] Adding key name when creating server and floating ip methods --- .../openstack/nova/NovaAsyncClient.java | 23 +++ .../jclouds/openstack/nova/NovaClient.java | 26 +++ .../openstack/nova/domain/FloatingIP.java | 169 ++++++++++++++++++ .../nova/options/CreateServerOptions.java | 20 ++- .../openstack/nova/NovaAsyncClientTest.java | 61 ++++++- .../ParseFloatingIPFromJsonResponse.java | 72 ++++++++ .../ParseFloatingIPListFromJsonResponse.java | 62 +++++++ .../test/resources/test_get_floatingip.json | 9 + .../test/resources/test_list_floatingips.json | 10 ++ 9 files changed, 449 insertions(+), 3 deletions(-) create mode 100644 apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java create mode 100644 apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPFromJsonResponse.java create mode 100644 apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPListFromJsonResponse.java create mode 100644 apis/nova/src/test/resources/test_get_floatingip.json create mode 100644 apis/nova/src/test/resources/test_list_floatingips.json diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java index 0423aa294c..874706a744 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java @@ -317,5 +317,28 @@ public interface NovaAsyncClient { @Path("/servers/{id}/ips/private") @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) ListenableFuture> listPrivateAddresses(@PathParam("id") int serverId); + + @POST + @Path("/servers/{id}/action") + @Consumes + @Produces(MediaType.APPLICATION_JSON) + @Payload("%7B\"addFloatingIp\":%7B\"address\":\"{address}\"%7D%7D") + ListenableFuture addFloatingIp(@PathParam("id") int serverId, @PayloadParam("address") String ip); + + @GET + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + @QueryParams(keys = "format", values = "json") + @Path("/os-floating-ips") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listFloatingIPs(); + + @GET + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + @QueryParams(keys = "format", values = "json") + @Path("/os-floating-ips/{id}") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getFloatingIP(@PathParam("id") int id); } diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java index 56ab0d8f05..768959690e 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java @@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit; import org.jclouds.concurrent.Timeout; import org.jclouds.openstack.nova.domain.Addresses; import org.jclouds.openstack.nova.domain.Flavor; +import org.jclouds.openstack.nova.domain.FloatingIP; import org.jclouds.openstack.nova.domain.Image; import org.jclouds.openstack.nova.domain.RebootType; import org.jclouds.openstack.nova.domain.Server; @@ -281,4 +282,29 @@ public interface NovaClient { */ Set listPrivateAddresses(int serverId); + /** + * Add a floating IP to the given server. The floating IP can just be added + * if the server has a fixed IP. It means that it is not possible to + * directly add the floating IP just after creating the server but have to + * poll if the server has an IP. + * + * @param serverId + * @param ip + */ + void addFloatingIp(int serverId, String ip); + + /** + * Get all the defined floating IPs + * + * @return + */ + Set listFloatingIPs(); + + /** + * Get floating IP details from its ID + * + * @param id the floating IP id + * @return the floating IP or null if not found + */ + FloatingIP getFloatingIP(int id); } diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java new file mode 100644 index 0000000000..591f2034f7 --- /dev/null +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java @@ -0,0 +1,169 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.domain; + +import com.google.gson.annotations.SerializedName; + +/** + * Check Floating IP Wiki page + * + * @author chamerling + * + */ +public class FloatingIP extends Resource { + + private int id; + + private String ip; + + @SerializedName(value="fixed_ip") + private String fixedIP; + + @SerializedName(value = "instance_id") + private int instanceID; + + @SuppressWarnings("unused") + private FloatingIP() { + } + + public FloatingIP(int id, String ip, String fixedIP, int instanceID) { + this.id = id; + this.ip = ip; + this.fixedIP = fixedIP; + this.instanceID = instanceID; + } + + /** + * @return the id + */ + public int getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return the ip + */ + public String getIp() { + return ip; + } + + /** + * @param ip the ip to set + */ + public void setIp(String ip) { + this.ip = ip; + } + + /** + * @return the fixedIP + */ + public String getFixedIP() { + return fixedIP; + } + + /** + * @param fixedIP the fixedIP to set + */ + public void setFixedIP(String fixedIP) { + this.fixedIP = fixedIP; + } + + /** + * @return the instanceID + */ + public int getInstanceID() { + return instanceID; + } + + /** + * @param instanceID the instanceID to set + */ + public void setInstanceID(int instanceID) { + this.instanceID = instanceID; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("FloatingIP [id="); + builder.append(id); + builder.append(", ip="); + builder.append(ip); + builder.append(", fixedIP="); + builder.append(fixedIP); + builder.append(", instanceID="); + builder.append(instanceID); + builder.append("]"); + return builder.toString(); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((fixedIP == null) ? 0 : fixedIP.hashCode()); + result = prime * result + id; + result = prime * result + instanceID; + result = prime * result + ((ip == null) ? 0 : ip.hashCode()); + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @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 != other.id) + return false; + if (instanceID != other.instanceID) + return false; + if (ip == null) { + if (other.ip != null) + return false; + } else if (!ip.equals(other.ip)) + return false; + return true; + } + +} diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java index 97f69a944e..1d024bf7a0 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java @@ -76,6 +76,7 @@ public class CreateServerOptions implements MapBinder { final String flavorRef; Map metadata; List personality; + String key_name; private ServerRequest(String name, String imageRef, String flavorRef) { this.name = name; @@ -87,6 +88,7 @@ public class CreateServerOptions implements MapBinder { private Map metadata = Maps.newHashMap(); private List files = Lists.newArrayList(); + private String keyName; @Override public R bindToRequest(R request, Map postParams) { @@ -97,6 +99,8 @@ public class CreateServerOptions implements MapBinder { server.metadata = metadata; if (files.size() > 0) server.personality = files; + if (keyName != null) + server.key_name = keyName; return bindToRequest(request, ImmutableMap.of("server", server)); } @@ -143,7 +147,13 @@ public class CreateServerOptions implements MapBinder { this.metadata = metadata; return this; } - + + public CreateServerOptions withKeyName(String keyName) { + checkNotNull(keyName, "keyName"); + this.keyName = keyName; + return this; + } + public static class Builder { /** @@ -161,6 +171,14 @@ public class CreateServerOptions implements MapBinder { CreateServerOptions options = new CreateServerOptions(); return options.withMetadata(metadata); } + + /** + * @see CreateServerOptions#withKeyPair(String) + */ + public static CreateServerOptions withKeyName(String keyName) { + CreateServerOptions options = new CreateServerOptions(); + return options.withKeyName(keyName); + } } @Override diff --git a/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java b/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java index 47d84448c1..79e4898b7f 100644 --- a/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java +++ b/apis/nova/src/test/java/org/jclouds/openstack/nova/NovaAsyncClientTest.java @@ -58,6 +58,7 @@ import static org.jclouds.openstack.nova.options.CreateServerOptions.Builder.wit import static org.jclouds.openstack.nova.options.ListOptions.Builder.changesSince; import static org.jclouds.openstack.nova.options.ListOptions.Builder.withDetails; import static org.jclouds.openstack.nova.options.RebuildServerOptions.Builder.withImage; +//import static org.junit.Assert.*; import static org.testng.Assert.assertEquals; /** @@ -132,6 +133,26 @@ public class NovaAsyncClientTest extends RestClientTest { checkFilters(request); + } + + @Test + public void testCreateServerWithKeyName() throws Exception { + Method method = NovaAsyncClient.class.getMethod("createServer", String.class, String.class, String.class, + createServerOptionsVarargsClass); + HttpRequest request = processor.createRequest(method, "ralphie", 2, 1, + withMetadata(ImmutableMap.of("foo", "bar")).withKeyName("mykey")); + + assertRequestLineEquals(request, "POST http://endpoint/vapi-version/servers?format=json HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Accept: application/json\n"); + assertPayloadEquals(request, + "{\"server\":{\"name\":\"ralphie\",\"imageRef\":\"2\",\"flavorRef\":\"1\",\"metadata\":{\"foo\":\"bar\"},\"key_name\":\"mykey\"}}", + "application/json", false); + + assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(request); } public void testDeleteImage() throws IOException, SecurityException, NoSuchMethodException { @@ -635,8 +656,44 @@ public class NovaAsyncClientTest extends RestClientTest { assertExceptionParserClassEquals(method, null); checkFilters(request); - } - + } + + public void testGetFloatingIP() throws SecurityException, + NoSuchMethodException { + Method method = NovaAsyncClient.class.getMethod("getFloatingIP", + int.class); + HttpRequest request = processor.createRequest(method, 2); + + assertRequestLineEquals(request, + "GET http://endpoint/vapi-version/os-floating-ips/2?format=json HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Accept: application/json\n"); + assertPayloadEquals(request, null, null, false); + + assertResponseParserClassEquals(method, request, + UnwrapOnlyJsonValue.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, + ReturnNullOnNotFoundOr404.class); + + checkFilters(request); + } + + public void testListFloatingIPs() throws SecurityException, NoSuchMethodException { + Method method = NovaAsyncClient.class.getMethod("listFloatingIPs"); + HttpRequest request = processor.createRequest(method); + + assertRequestLineEquals(request, + "GET http://endpoint/vapi-version/os-floating-ips?format=json HTTP/1.1"); + assertNonPayloadHeadersEqual(request, "Accept: application/json\n"); + assertPayloadEquals(request, null, null, false); + + assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class); + + checkFilters(request); + } + @Override protected TypeLiteral> createTypeLiteral() { return new TypeLiteral>() { diff --git a/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPFromJsonResponse.java b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPFromJsonResponse.java new file mode 100644 index 0000000000..9d666654c2 --- /dev/null +++ b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPFromJsonResponse.java @@ -0,0 +1,72 @@ +/** + * 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.functions; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.io.IOException; +import java.io.InputStream; + +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.UnwrapOnlyJsonValue; +import org.jclouds.io.Payloads; +import org.jclouds.json.config.GsonModule; +import org.jclouds.openstack.nova.domain.FloatingIP; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; + +/** + * @author chamerling + * + */ +@Test(groups = "unit") +public class ParseFloatingIPFromJsonResponse { + + @Test + public void testParseFloatingIPFromJsonResponseTest() throws IOException { + FloatingIP response = parseFLoatingIP(); + + String json = new Gson().toJson(response); + assertNotNull(json); + + assertEquals(response.getId(), 1); + assertEquals(response.getFixedIP(), "10.0.0.2"); + assertEquals(response.getInstanceID(), 123); + assertEquals(response.getIp(), "10.0.0.3"); + } + + public static FloatingIP parseFLoatingIP() { + Injector i = Guice.createInjector(new GsonModule()); + + InputStream is = ParseFloatingIPFromJsonResponse.class + .getResourceAsStream("/test_get_floatingip.json"); + + UnwrapOnlyJsonValue parser = i.getInstance(Key + .get(new TypeLiteral>() { + })); + return parser.apply(new HttpResponse(200, "ok", Payloads + .newInputStreamPayload(is))); + } +} diff --git a/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPListFromJsonResponse.java b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPListFromJsonResponse.java new file mode 100644 index 0000000000..a198a35cef --- /dev/null +++ b/apis/nova/src/test/java/org/jclouds/openstack/nova/functions/ParseFloatingIPListFromJsonResponse.java @@ -0,0 +1,62 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.functions; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; +import java.net.UnknownHostException; +import java.util.List; + +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.UnwrapOnlyJsonValue; +import org.jclouds.io.Payloads; +import org.jclouds.json.config.GsonModule; +import org.jclouds.openstack.nova.domain.FloatingIP; +import org.testng.annotations.Test; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; + +/** + * @author chamerling + * + */ +@Test(groups = "unit") +public class ParseFloatingIPListFromJsonResponse { + Injector i = Guice.createInjector(new GsonModule()); + + @Test + public void testParseFloatingIPListFromJsonResponseTest() throws UnknownHostException { + InputStream is = getClass().getResourceAsStream( + "/test_list_floatingips.json"); + + UnwrapOnlyJsonValue> parser = i.getInstance(Key + .get(new TypeLiteral>>() { + })); + List response = parser.apply(new HttpResponse(200, "ok", + Payloads.newInputStreamPayload(is))); + + assertEquals(response.size(), 1); + FloatingIP floatingIP = new FloatingIP(1, "10.0.0.3", "11.0.0.1", 12); + assertEquals(response.get(0), floatingIP); + } +} diff --git a/apis/nova/src/test/resources/test_get_floatingip.json b/apis/nova/src/test/resources/test_get_floatingip.json new file mode 100644 index 0000000000..c2411fd65f --- /dev/null +++ b/apis/nova/src/test/resources/test_get_floatingip.json @@ -0,0 +1,9 @@ +{ + "floating_ip" : + { + "id" : 1, + "ip" : "10.0.0.3", + "fixed_ip" : "10.0.0.2", + "instance_id" : 123 + } +} \ No newline at end of file diff --git a/apis/nova/src/test/resources/test_list_floatingips.json b/apis/nova/src/test/resources/test_list_floatingips.json new file mode 100644 index 0000000000..f4910cb9b6 --- /dev/null +++ b/apis/nova/src/test/resources/test_list_floatingips.json @@ -0,0 +1,10 @@ +{ + "floating_ips" : [ + { + "id" : 1, + "ip" : "10.0.0.3", + "fixed_ip": "11.0.0.1", + "instance_id": 12 + } + ] +} \ No newline at end of file From 4bc4008b82cb2f4ad37f5b76f44d79ba1f3f68a3 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 13:33:56 +0200 Subject: [PATCH 21/82] Add GlobalHost[Async]Client.addHost() --- .../features/GlobalHostAsyncClient.java | 19 +++ .../cloudstack/features/GlobalHostClient.java | 14 +++ .../cloudstack/options/AddHostOptions.java | 115 ++++++++++++++++++ .../features/GlobalHostClientExpectTest.java | 23 ++++ .../options/AddHostOptionsTest.java | 87 +++++++++++++ .../src/test/resources/addhostresponse.json | 2 + 6 files changed, 260 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddHostOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddHostOptionsTest.java create mode 100644 apis/cloudstack/src/test/resources/addhostresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index a6fc4d05f0..871818ae21 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.filters.QuerySigner; +import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; import org.jclouds.rest.annotations.ExceptionParser; @@ -32,6 +33,7 @@ import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import java.util.Set; @@ -57,6 +59,23 @@ public interface GlobalHostAsyncClient { @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) ListenableFuture> listHosts(ListHostsOptions... options); + /** + * Adds a new host. + * + * @param zoneId the Zone ID for the host + * @param url the host URL + * @param hypervisor hypervisor type of the host + * @param username the username for the host + * @param password the password for the host + * @param options optional arguments + * @return the new host. + */ + @GET + @QueryParams(keys = "command", values = "addHost") + @SelectJson("host") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture addHost(@QueryParam("zoneid") long zoneId, @QueryParam("url") String url, @QueryParam("hypervisor") String hypervisor, @QueryParam("username") String username, @QueryParam("password") String password, AddHostOptions... options); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 414ce8b6fa..6006c91458 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -20,6 +20,7 @@ package org.jclouds.cloudstack.features; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; +import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; import org.jclouds.concurrent.Timeout; @@ -48,6 +49,19 @@ public interface GlobalHostClient { */ Set listHosts(ListHostsOptions... options); + /** + * Adds a new host. + * + * @param zoneId the Zone ID for the host + * @param url the host URL + * @param hypervisor hypervisor type of the host + * @param username the username for the host + * @param password the password for the host + * @param options optional arguments + * @return the new host. + */ + Host addHost(long zoneId, String url, String hypervisor, String username, String password, AddHostOptions... options); + /** * Lists clusters * diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddHostOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddHostOptions.java new file mode 100644 index 0000000000..5cdf4bb70b --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddHostOptions.java @@ -0,0 +1,115 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.domain.Host; +import org.jclouds.http.options.BaseHttpRequestOptions; + +import java.util.Set; + +/** + * Options to the GlobalHostClient.addHost() API call + * + * @author Richard Downer + */ +public class AddHostOptions extends BaseHttpRequestOptions { + + public static final AddHostOptions NONE = new AddHostOptions(); + + /** + * @param allocationState Allocation state of this Host for allocation of new resources + */ + public AddHostOptions allocationState(Host.AllocationState allocationState) { + this.queryParameters.replaceValues("allocationstate", ImmutableSet.of(allocationState.toString())); + return this; + } + + /** + * @param clusterId the cluster ID for the host + */ + public AddHostOptions clusterId(long clusterId) { + this.queryParameters.replaceValues("clusterid", ImmutableSet.of(clusterId + "")); + return this; + } + + /** + * @param clusterName the cluster name for the host + */ + public AddHostOptions clusterName(String clusterName) { + this.queryParameters.replaceValues("clustername", ImmutableSet.of(clusterName)); + return this; + } + + /** + * @param hostTags list of tags to be added to the host + */ + public AddHostOptions hostTags(Set hostTags) { + this.queryParameters.replaceValues("hosttags", ImmutableSet.of(Joiner.on(',').join(hostTags))); + return this; + } + + /** + * @param podId the Pod ID for the host + */ + public AddHostOptions podId(long podId) { + this.queryParameters.replaceValues("podid", ImmutableSet.of(podId + "")); + return this; + } + + public static class Builder { + + /** + * @param allocationState Allocation state of this Host for allocation of new resources + */ + public static AddHostOptions allocationState(Host.AllocationState allocationState) { + return new AddHostOptions().allocationState(allocationState); + } + + /** + * @param clusterId the cluster ID for the host + */ + public static AddHostOptions clusterId(long clusterId) { + return new AddHostOptions().clusterId(clusterId); + } + + /** + * @param clusterName the cluster name for the host + */ + public static AddHostOptions clusterName(String clusterName) { + return new AddHostOptions().clusterName(clusterName); + } + + /** + * @param hostTags list of tags to be added to the host + */ + public static AddHostOptions hostTags(Set hostTags) { + return new AddHostOptions().hostTags(hostTags); + } + + /** + * @param podId the Pod ID for the host + */ + public static AddHostOptions podId(long podId) { + return new AddHostOptions().podId(podId); + } + + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 89ac050f04..a2c5c82490 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -25,12 +25,14 @@ import org.jclouds.cloudstack.CloudStackContext; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.ConfigurationEntry; import org.jclouds.cloudstack.domain.Host; +import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.testng.annotations.Test; import java.net.URI; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.Set; import java.util.TimeZone; @@ -94,6 +96,27 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(client.listHosts(), ImmutableSet.of()); } + @Test + public void testAddHostWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=addHost&zoneid=1&hypervisor=XenServer&url=http%3A%2F%2Fexample.com&username=fred&password=sekrit&hosttags=&allocationstate=Enabled&clusterid=1&clustername=Xen%20Clust%201&podid=1&apiKey=identity&signature=ExGaljKKQIlVbWk5hd0BnnjmBzs%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/addhostresponse.json")) + .statusCode(200).build(); + + Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC"); + Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "UTC"); + Host expected = Host.builder().id(1).name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId(223098941760041L).clusterId(1).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build(); + + Host actual = requestSendsResponse(request, response).addHost(1, "http://example.com", "XenServer", "fred", "sekrit", + AddHostOptions.Builder.hostTags(Collections.emptySet()).allocationState(Host.AllocationState.ENABLED).clusterId(1).clusterName("Xen Clust 1").podId(1)); + + assertEquals(actual, expected); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddHostOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddHostOptionsTest.java new file mode 100644 index 0000000000..7dfd22fb7e --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddHostOptionsTest.java @@ -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.cloudstack.options; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.domain.Host; +import org.testng.annotations.Test; + +import static org.jclouds.cloudstack.options.AddHostOptions.Builder.*; +import static org.testng.Assert.assertEquals; + +/** + * Tests behavior of {@code AddHostOptions} + * + * @author Richard Downer + */ +@Test(groups = "unit") +public class AddHostOptionsTest { + + public void testAllocationState() { + AddHostOptions options = new AddHostOptions().allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testAllocationStateStatic() { + AddHostOptions options = allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testClusterId() { + AddHostOptions options = new AddHostOptions().clusterId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("clusterid")); + } + + public void testClusterIdStatic() { + AddHostOptions options = clusterId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("clusterid")); + } + + public void testClusterName() { + AddHostOptions options = new AddHostOptions().clusterName("Cluster Name"); + assertEquals(ImmutableList.of("Cluster Name"), options.buildQueryParameters().get("clustername")); + } + + public void testClusterNameStatic() { + AddHostOptions options = clusterName("Cluster Name"); + assertEquals(ImmutableList.of("Cluster Name"), options.buildQueryParameters().get("clustername")); + } + + public void testHostTags() { + AddHostOptions options = new AddHostOptions().hostTags(ImmutableSet.of("foo", "bar", "baz")); + assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags")); + } + + public void testHostTagsStatic() { + AddHostOptions options = hostTags(ImmutableSet.of("foo", "bar", "baz")); + assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags")); + } + + public void testPodId() { + AddHostOptions options = new AddHostOptions().podId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid")); + } + + public void testPodIdStatic() { + AddHostOptions options = podId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid")); + } + +} diff --git a/apis/cloudstack/src/test/resources/addhostresponse.json b/apis/cloudstack/src/test/resources/addhostresponse.json new file mode 100644 index 0000000000..7508410682 --- /dev/null +++ b/apis/cloudstack/src/test/resources/addhostresponse.json @@ -0,0 +1,2 @@ +{ "addhostresponse" : { "host" : + {"warning":"This test data is fabricated","id":1,"name":"cs2-xevsrv.alucloud.local","state":"Up","type":"Routing","ipaddress":"10.26.26.107","zoneid":1,"zonename":"Dev Zone 1","podid":1,"podname":"Dev Pod 1","version":"2.2.12.20110928142833","hypervisor":"XenServer","cpunumber":24,"cpuspeed":2266,"cpuallocated":"2.76%","cpuused":"0.1%","cpuwithoverprovisioning":"54384.0","networkkbsread":4443,"networkkbswrite":15048,"memorytotal":100549733760,"memoryallocated":3623878656,"memoryused":3623878656,"capabilities":"xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64","lastpinged":"1970-01-16T00:54:43+0200","managementserverid":223098941760041,"clusterid":1,"clustername":"Xen Clust 1","clustertype":"CloudManaged","islocalstorageactive":false,"created":"2011-11-26T23:28:36+0200","events":"PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping","hosttags":"","hasEnoughCapacity":false,"allocationstate":"Enabled"} } } \ No newline at end of file From 9bb9312d4a23f99c057d50ce51fbc1d12c675095 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 13:55:32 +0200 Subject: [PATCH 22/82] Add GlobalHost[Async]Client.updateHost() --- .../features/GlobalHostAsyncClient.java | 14 +++ .../cloudstack/features/GlobalHostClient.java | 10 +++ .../cloudstack/options/UpdateHostOptions.java | 87 +++++++++++++++++++ .../features/GlobalHostClientExpectTest.java | 21 +++++ .../options/UpdateHostOptionsTest.java | 67 ++++++++++++++ .../test/resources/updatehostresponse.json | 2 + 6 files changed, 201 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateHostOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateHostOptionsTest.java create mode 100644 apis/cloudstack/src/test/resources/updatehostresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 871818ae21..46328fc9a3 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -25,6 +25,7 @@ import org.jclouds.cloudstack.filters.QuerySigner; import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; +import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.RequestFilters; @@ -76,6 +77,19 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) ListenableFuture addHost(@QueryParam("zoneid") long zoneId, @QueryParam("url") String url, @QueryParam("hypervisor") String hypervisor, @QueryParam("username") String username, @QueryParam("password") String password, AddHostOptions... options); + /** + * Updates a host. + * + * @param hostId the ID of the host to update + * @param options optional arguments + * @return the modified host. + */ + @GET + @QueryParams(keys = "command", values = "updateHost") + @SelectJson("host") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture updateHost(@QueryParam("id") long hostId, UpdateHostOptions... options); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 6006c91458..0dceadd261 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -23,6 +23,7 @@ import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; +import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.concurrent.Timeout; import java.util.Set; @@ -62,6 +63,15 @@ public interface GlobalHostClient { */ Host addHost(long zoneId, String url, String hypervisor, String username, String password, AddHostOptions... options); + /** + * Updates a host. + * + * @param hostId the ID of the host to update + * @param options optional arguments + * @return the modified host. + */ + Host updateHost(long hostId, UpdateHostOptions... options); + /** * Lists clusters * diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateHostOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateHostOptions.java new file mode 100644 index 0000000000..e89013ae92 --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateHostOptions.java @@ -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.cloudstack.options; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.domain.Host; +import org.jclouds.functions.JoinOnComma; +import org.jclouds.http.options.BaseHttpRequestOptions; + +import java.util.Set; + +/** + * Options to the GlobalHostClient.addHost() API call + * + * @author Richard Downer + */ +public class UpdateHostOptions extends BaseHttpRequestOptions { + + + public static final UpdateHostOptions NONE = new UpdateHostOptions(); + + /** + * @param allocationState Allocation state of this Host for allocation of new resources + */ + public UpdateHostOptions allocationState(Host.AllocationState allocationState) { + this.queryParameters.replaceValues("allocationstate", ImmutableSet.of(allocationState.toString())); + return this; + } + + /** + * @param hostTags list of tags to be added to the host + */ + public UpdateHostOptions hostTags(Set hostTags) { + this.queryParameters.replaceValues("hosttags", ImmutableSet.of(Joiner.on(',').join(hostTags))); + return this; + } + + /** + * @param osCategoryId the id of Os category to update the host with + */ + public UpdateHostOptions osCategoryId(long osCategoryId) { + this.queryParameters.replaceValues("oscategoryid", ImmutableSet.of(osCategoryId + "")); + return this; + } + + public static class Builder { + + /** + * @param allocationState Allocation state of this Host for allocation of new resources + */ + public static UpdateHostOptions allocationState(Host.AllocationState allocationState) { + return new UpdateHostOptions().allocationState(allocationState); + } + + /** + * @param hostTags list of tags to be added to the host + */ + public static UpdateHostOptions hostTags(Set hostTags) { + return new UpdateHostOptions().hostTags(hostTags); + } + + /** + * @param podId the Pod ID for the host + */ + public static UpdateHostOptions osCategoryId(long osCategoryId) { + return new UpdateHostOptions().osCategoryId(osCategoryId); + } + + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index a2c5c82490..808b225382 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -26,6 +26,7 @@ import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.ConfigurationEntry; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.options.AddHostOptions; +import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.testng.annotations.Test; @@ -117,6 +118,26 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, expected); } + @Test + public void testUpdateHostWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateHost&id=1&allocationstate=Enabled&hosttags=&oscategoryid=5&apiKey=identity&signature=qTxNq9yQG8S108giqS%2FROFzgev8%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/updatehostresponse.json")) + .statusCode(200).build(); + + Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "UTC"); + Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "UTC"); + Host expected = Host.builder().id(1).name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId(1).zoneName("Dev Zone 1").podId(1).podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId(223098941760041L).clusterId(1).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build(); + + Host actual = requestSendsResponse(request, response).updateHost(1, UpdateHostOptions.Builder.allocationState(Host.AllocationState.ENABLED).hostTags(Collections.emptySet()).osCategoryId(5)); + + assertEquals(actual, expected); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateHostOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateHostOptionsTest.java new file mode 100644 index 0000000000..69ffc18592 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateHostOptionsTest.java @@ -0,0 +1,67 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.domain.Host; +import org.testng.annotations.Test; + +import static org.jclouds.cloudstack.options.UpdateHostOptions.Builder.*; +import static org.testng.Assert.assertEquals; + +/** + * Tests behavior of {@code UpdateHostOptions} + * + * @author Richard Downer + */ +@Test(groups = "unit") +public class UpdateHostOptionsTest { + + public void testAllocationState() { + UpdateHostOptions options = new UpdateHostOptions().allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testAllocationStateStatic() { + UpdateHostOptions options = allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testHostTags() { + UpdateHostOptions options = new UpdateHostOptions().hostTags(ImmutableSet.of("foo", "bar", "baz")); + assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags")); + } + + public void testHostTagsStatic() { + UpdateHostOptions options = hostTags(ImmutableSet.of("foo", "bar", "baz")); + assertEquals(ImmutableList.of("foo,bar,baz"), options.buildQueryParameters().get("hosttags")); + } + + public void testOsCategoryId() { + UpdateHostOptions options = new UpdateHostOptions().osCategoryId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("oscategoryid")); + } + + public void testOsCategoryIdStatic() { + UpdateHostOptions options = osCategoryId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("oscategoryid")); + } + +} diff --git a/apis/cloudstack/src/test/resources/updatehostresponse.json b/apis/cloudstack/src/test/resources/updatehostresponse.json new file mode 100644 index 0000000000..cb70ddd6bf --- /dev/null +++ b/apis/cloudstack/src/test/resources/updatehostresponse.json @@ -0,0 +1,2 @@ +{ "updatehostresponse" : { "host" : + {"warning":"This test data is fabricated","id":1,"name":"cs2-xevsrv.alucloud.local","state":"Up","type":"Routing","ipaddress":"10.26.26.107","zoneid":1,"zonename":"Dev Zone 1","podid":1,"podname":"Dev Pod 1","version":"2.2.12.20110928142833","hypervisor":"XenServer","cpunumber":24,"cpuspeed":2266,"cpuallocated":"2.76%","cpuused":"0.1%","cpuwithoverprovisioning":"54384.0","networkkbsread":4443,"networkkbswrite":15048,"memorytotal":100549733760,"memoryallocated":3623878656,"memoryused":3623878656,"capabilities":"xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64","lastpinged":"1970-01-16T00:54:43+0200","managementserverid":223098941760041,"clusterid":1,"clustername":"Xen Clust 1","clustertype":"CloudManaged","islocalstorageactive":false,"created":"2011-11-26T23:28:36+0200","events":"PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping","hosttags":"","hasEnoughCapacity":false,"allocationstate":"Enabled"} } } \ No newline at end of file From 2b1c5f78f3bbe80b654380eb81d6d80a55258378 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 14:06:57 +0200 Subject: [PATCH 23/82] Add GlobalHost[Async]Client.updateHostPassword() --- .../cloudstack/features/GlobalHostAsyncClient.java | 12 ++++++++++++ .../cloudstack/features/GlobalHostClient.java | 9 +++++++++ .../features/GlobalHostClientExpectTest.java | 13 +++++++++++++ 3 files changed, 34 insertions(+) diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 46328fc9a3..975f6cd442 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -90,6 +90,18 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) ListenableFuture updateHost(@QueryParam("id") long hostId, UpdateHostOptions... options); + /** + * Update password of a host on management server. + * + * @param hostId the host ID + * @param username the username for the host + * @param password the password for the host + */ + @GET + @QueryParams(keys = "command", values = "updateHostPassword") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture updateHostPassword(@QueryParam("hostid") long hostId, @QueryParam("username") String username, @QueryParam("password") String password); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 0dceadd261..098bca3ad2 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -72,6 +72,15 @@ public interface GlobalHostClient { */ Host updateHost(long hostId, UpdateHostOptions... options); + /** + * Update password of a host on management server. + * + * @param hostId the host ID + * @param username the username for the host + * @param password the password for the host + */ + void updateHostPassword(long hostId, String username, String password); + /** * Lists clusters * diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 808b225382..cb2e01de7b 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -138,6 +138,19 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, expected); } + @Test + public void testUpdateHostPasswordWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateHostPassword&hostid=1&password=sekrit&username=fred&apiKey=identity&signature=g9nMKDWoiU72y0HhaRFekZCgfJc%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .statusCode(200).build(); + + requestSendsResponse(request, response).updateHostPassword(1, "fred", "sekrit"); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() From 350e01c2308164a68584d6c943fd78122180228c Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 14:13:23 +0200 Subject: [PATCH 24/82] Add GlobalHost[Async]Client.deleteHost() --- .../features/GlobalHostAsyncClient.java | 12 ++++ .../cloudstack/features/GlobalHostClient.java | 9 +++ .../cloudstack/options/DeleteHostOptions.java | 66 +++++++++++++++++++ .../features/GlobalHostClientExpectTest.java | 14 ++++ .../options/DeleteHostOptionsTest.java | 57 ++++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteHostOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteHostOptionsTest.java diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 975f6cd442..5726aacca4 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -23,6 +23,7 @@ import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.filters.QuerySigner; import org.jclouds.cloudstack.options.AddHostOptions; +import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; import org.jclouds.cloudstack.options.UpdateHostOptions; @@ -102,6 +103,17 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) ListenableFuture updateHostPassword(@QueryParam("hostid") long hostId, @QueryParam("username") String username, @QueryParam("password") String password); + /** + * Deletes a host. + * + * @param hostId the host ID + * @param options optional arguments + */ + @GET + @QueryParams(keys = "command", values = "deleteHost") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture deleteHost(@QueryParam("id") long hostId, DeleteHostOptions... options); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 098bca3ad2..22a83f1352 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -21,6 +21,7 @@ package org.jclouds.cloudstack.features; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.options.AddHostOptions; +import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; import org.jclouds.cloudstack.options.UpdateHostOptions; @@ -81,6 +82,14 @@ public interface GlobalHostClient { */ void updateHostPassword(long hostId, String username, String password); + /** + * Deletes a host. + * + * @param hostId the host ID + * @param options optional arguments + */ + void deleteHost(long hostId, DeleteHostOptions... options); + /** * Lists clusters * diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteHostOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteHostOptions.java new file mode 100644 index 0000000000..f8d3a12edf --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/DeleteHostOptions.java @@ -0,0 +1,66 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Options to the GlobalHostClient.deleteHost() API call + * + * @author Richard Downer + */ +public class DeleteHostOptions extends BaseHttpRequestOptions { + + public static final DeleteHostOptions NONE = new DeleteHostOptions(); + + /** + * @param forced Force delete the host. All HA enabled vms running on the host will be put to HA; HA disabled ones will be stopped + */ + public DeleteHostOptions forced(boolean forced) { + this.queryParameters.replaceValues("forced", ImmutableSet.of(forced + "")); + return this; + } + + /** + * @param forceDestroyLocalStorage Force destroy local storage on this host. All VMs created on this local storage will be destroyed + */ + public DeleteHostOptions forceDestroyLocalStorage(boolean forceDestroyLocalStorage) { + this.queryParameters.replaceValues("forcedestroylocalstorage", ImmutableSet.of(forceDestroyLocalStorage + "")); + return this; + } + + public static class Builder { + + /** + * @param forced Force delete the host. All HA enabled vms running on the host will be put to HA; HA disabled ones will be stopped + */ + public static DeleteHostOptions forced(boolean forced) { + return new DeleteHostOptions().forced(forced); + } + + /** + * @param forceDestroyLocalStorage Force destroy local storage on this host. All VMs created on this local storage will be destroyed + */ + public static DeleteHostOptions forceDestroyLocalStorage(boolean forceDestroyLocalStorage) { + return new DeleteHostOptions().forceDestroyLocalStorage(forceDestroyLocalStorage); + } + + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index cb2e01de7b..034e29df51 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -26,6 +26,7 @@ import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.ConfigurationEntry; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.options.AddHostOptions; +import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; @@ -151,6 +152,19 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe requestSendsResponse(request, response).updateHostPassword(1, "fred", "sekrit"); } + @Test + public void testDeleteHostWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=deleteHost&id=1&forced=true&forcedestroylocalstorage=true&apiKey=identity&signature=ZdvO1BWBkdPiDAjsVlKtqDe6N7k%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .statusCode(200).build(); + + requestSendsResponse(request, response).deleteHost(1, DeleteHostOptions.Builder.forced(true).forceDestroyLocalStorage(true)); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteHostOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteHostOptionsTest.java new file mode 100644 index 0000000000..0445a2e926 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/DeleteHostOptionsTest.java @@ -0,0 +1,57 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.domain.Host; +import org.testng.annotations.Test; + +import static org.jclouds.cloudstack.options.DeleteHostOptions.Builder.*; +import static org.testng.Assert.assertEquals; + +/** + * Tests behavior of {@code DeleteHostOptions} + * + * @author Richard Downer + */ +@Test(groups = "unit") +public class DeleteHostOptionsTest { + + public void testForced() { + DeleteHostOptions options = new DeleteHostOptions().forced(true); + assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forced")); + } + + public void testForcedStatic() { + DeleteHostOptions options = forced(true); + assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forced")); + } + + public void testForceDestroyLocalStorage() { + DeleteHostOptions options = new DeleteHostOptions().forceDestroyLocalStorage(true); + assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forcedestroylocalstorage")); + } + + public void testForceDestroyLocalStorageStatic() { + DeleteHostOptions options = forceDestroyLocalStorage(true); + assertEquals(ImmutableList.of("true"), options.buildQueryParameters().get("forcedestroylocalstorage")); + } + +} From b3bb99da8857d7362e170775adac822a56ffa669 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 14:25:24 +0200 Subject: [PATCH 25/82] Add GlobalHost[Async]Client.prepareHostForMaintenance() --- .../features/GlobalHostAsyncClient.java | 12 ++++++++++++ .../cloudstack/features/GlobalHostClient.java | 8 ++++++++ .../features/GlobalHostClientExpectTest.java | 15 +++++++++++++++ .../preparehostformaintenanceresponse.json | 1 + 4 files changed, 36 insertions(+) create mode 100644 apis/cloudstack/src/test/resources/preparehostformaintenanceresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 5726aacca4..0041d934ae 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -114,6 +114,18 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) ListenableFuture deleteHost(@QueryParam("id") long hostId, DeleteHostOptions... options); + /** + * Prepares a host for maintenance. + * + * @param hostId the host ID + * @return a job reference number for tracking this asynchronous job. + */ + @GET + @QueryParams(keys = "command", values = "prepareHostForMaintenance") + @SelectJson("jobid") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture prepareHostForMaintenance(@QueryParam("id") long hostId); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 22a83f1352..54417f3256 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -90,6 +90,14 @@ public interface GlobalHostClient { */ void deleteHost(long hostId, DeleteHostOptions... options); + /** + * Prepares a host for maintenance. + * + * @param hostId the host ID + * @return a job reference number for tracking this asynchronous job. + */ + Long prepareHostForMaintenance(long hostId); + /** * Lists clusters * diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 034e29df51..a2e66866be 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -165,6 +165,21 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe requestSendsResponse(request, response).deleteHost(1, DeleteHostOptions.Builder.forced(true).forceDestroyLocalStorage(true)); } + @Test + public void testPrepareHostForMaintenanceWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=prepareHostForMaintenance&id=1&apiKey=identity&signature=9tDwdox%2FxAKmZr9kVrR6Ttnxf3U%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/preparehostformaintenanceresponse.json")) + .statusCode(200).build(); + + Long actual = requestSendsResponse(request, response).prepareHostForMaintenance(1); + assertEquals(actual, Long.valueOf(2036L)); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() diff --git a/apis/cloudstack/src/test/resources/preparehostformaintenanceresponse.json b/apis/cloudstack/src/test/resources/preparehostformaintenanceresponse.json new file mode 100644 index 0000000000..294f6464f2 --- /dev/null +++ b/apis/cloudstack/src/test/resources/preparehostformaintenanceresponse.json @@ -0,0 +1 @@ +{ "preparehostformaintenanceresponse" : {"warning":"this test data is fabricated","jobid":2036,"id":2017} } \ No newline at end of file From 528fa0ae5aa18456fcd2c5c96dd9dccd9372d3b6 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 14:31:03 +0200 Subject: [PATCH 26/82] Add GlobalHost[Async]Client.cancelHostMaintenance() --- .../features/GlobalHostAsyncClient.java | 12 ++++++++++++ .../cloudstack/features/GlobalHostClient.java | 8 ++++++++ .../features/GlobalHostClientExpectTest.java | 15 +++++++++++++++ .../resources/cancelhostmaintenanceresponse.json | 1 + 4 files changed, 36 insertions(+) create mode 100644 apis/cloudstack/src/test/resources/cancelhostmaintenanceresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 0041d934ae..70bfefcc8a 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -126,6 +126,18 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) ListenableFuture prepareHostForMaintenance(@QueryParam("id") long hostId); + /** + * Cancels host maintenance. + * + * @param hostId the host ID + * @return a job reference number for tracking this asynchronous job. + */ + @GET + @QueryParams(keys = "command", values = "cancelHostMaintenance") + @SelectJson("jobid") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture cancelHostMaintenance(@QueryParam("id") long hostId); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 54417f3256..434470c8fc 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -98,6 +98,14 @@ public interface GlobalHostClient { */ Long prepareHostForMaintenance(long hostId); + /** + * Cancels host maintenance. + * + * @param hostId the host ID + * @return a job reference number for tracking this asynchronous job. + */ + Long cancelHostMaintenance(long hostId); + /** * Lists clusters * diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index a2e66866be..24dd923d82 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -180,6 +180,21 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, Long.valueOf(2036L)); } + @Test + public void testCancelHostMaintenanceWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=cancelHostMaintenance&id=1&apiKey=identity&signature=9RduzuBoyRZKNTzAoVqUo9gRTfk%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/cancelhostmaintenanceresponse.json")) + .statusCode(200).build(); + + Long actual = requestSendsResponse(request, response).cancelHostMaintenance(1); + assertEquals(actual, Long.valueOf(2036L)); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() diff --git a/apis/cloudstack/src/test/resources/cancelhostmaintenanceresponse.json b/apis/cloudstack/src/test/resources/cancelhostmaintenanceresponse.json new file mode 100644 index 0000000000..5c3b0d0357 --- /dev/null +++ b/apis/cloudstack/src/test/resources/cancelhostmaintenanceresponse.json @@ -0,0 +1 @@ +{ "cancelhostmaintenanceresponse" : {"warning":"this test data is fabricated","jobid":2036,"id":2017} } \ No newline at end of file From 20f58c4a12654dc1259fcb0934e1efe20a884007 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 14:39:52 +0200 Subject: [PATCH 27/82] Add GlobalHost[Async]Client.reconnectHost() --- .../features/GlobalHostAsyncClient.java | 12 ++++++++++++ .../cloudstack/features/GlobalHostClient.java | 8 ++++++++ .../features/GlobalHostClientExpectTest.java | 15 +++++++++++++++ .../src/test/resources/reconnecthostresponse.json | 1 + 4 files changed, 36 insertions(+) create mode 100644 apis/cloudstack/src/test/resources/reconnecthostresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 70bfefcc8a..fe53dca3dc 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -138,6 +138,18 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) ListenableFuture cancelHostMaintenance(@QueryParam("id") long hostId); + /** + * Reconnects a host. + * + * @param hostId + * @return a job reference number for tracking this asynchronous job. + */ + @GET + @QueryParams(keys = "command", values = "reconnectHost") + @SelectJson("jobid") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture reconnectHost(@QueryParam("id") long hostId); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 434470c8fc..f422af69dd 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -106,6 +106,14 @@ public interface GlobalHostClient { */ Long cancelHostMaintenance(long hostId); + /** + * Reconnects a host. + * + * @param hostId + * @return a job reference number for tracking this asynchronous job. + */ + Long reconnectHost(long hostId); + /** * Lists clusters * diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 24dd923d82..acbba0beb9 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -195,6 +195,21 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, Long.valueOf(2036L)); } + @Test + public void testReconnectHostWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=reconnectHost&id=1&apiKey=identity&signature=wJEF02vwdyOnJOTa%2BWMMK906aRU%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/reconnecthostresponse.json")) + .statusCode(200).build(); + + Long actual = requestSendsResponse(request, response).reconnectHost(1); + assertEquals(actual, Long.valueOf(2036L)); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() diff --git a/apis/cloudstack/src/test/resources/reconnecthostresponse.json b/apis/cloudstack/src/test/resources/reconnecthostresponse.json new file mode 100644 index 0000000000..2b86f49790 --- /dev/null +++ b/apis/cloudstack/src/test/resources/reconnecthostresponse.json @@ -0,0 +1 @@ +{ "reconnecthostresponse" : {"warning":"this test data is fabricated","jobid":2036,"id":2017} } \ No newline at end of file From 533e13fc44e3398df93618787b035ef8dfcb707a Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 14:57:25 +0200 Subject: [PATCH 28/82] Add GlobalHost[Async]Client.addSecondaryStorage() --- .../features/GlobalHostAsyncClient.java | 14 +++++ .../cloudstack/features/GlobalHostClient.java | 10 ++++ .../options/AddSecondaryStorageOptions.java | 53 +++++++++++++++++++ .../features/GlobalHostClientExpectTest.java | 22 ++++++++ .../AddSecondaryStorageOptionsTest.java | 45 ++++++++++++++++ .../addsecondarystorageresponse.json | 3 ++ 6 files changed, 147 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptionsTest.java create mode 100644 apis/cloudstack/src/test/resources/addsecondarystorageresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index fe53dca3dc..9c46cd1367 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -23,6 +23,7 @@ import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.filters.QuerySigner; import org.jclouds.cloudstack.options.AddHostOptions; +import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; @@ -150,6 +151,19 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) ListenableFuture reconnectHost(@QueryParam("id") long hostId); + /** + * Adds secondary storage. + * + * @param url the URL for the secondary storage + * @param options optional arguments + * @return the host of the storage. + */ + @GET + @QueryParams(keys = "command", values = "addSecondaryStorage") + @SelectJson("host") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture addSecondaryStorage(@QueryParam("url") String url, AddSecondaryStorageOptions... options); + /** * @see GlobalHostClient#listClusters */ diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index f422af69dd..77ae55e023 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -21,6 +21,7 @@ package org.jclouds.cloudstack.features; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.options.AddHostOptions; +import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; @@ -114,6 +115,15 @@ public interface GlobalHostClient { */ Long reconnectHost(long hostId); + /** + * Adds secondary storage. + * + * @param url the URL for the secondary storage + * @param options optional arguments + * @return the host of the storage. + */ + Host addSecondaryStorage(String url, AddSecondaryStorageOptions... options); + /** * Lists clusters * diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptions.java new file mode 100644 index 0000000000..cfe8d5b146 --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptions.java @@ -0,0 +1,53 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Options for the GlobalHostClient.addSecondaryStorage() API call + * + * @author Richard Downer + */ +public class AddSecondaryStorageOptions extends BaseHttpRequestOptions { + + public static final AddSecondaryStorageOptions NONE = new AddSecondaryStorageOptions(); + + /** + * @param zoneId + * the ID of the zone + */ + public AddSecondaryStorageOptions zoneId(long zoneId) { + this.queryParameters.replaceValues("zoneid", ImmutableSet.of(zoneId + "")); + return this; + } + + public static class Builder { + + /** + * @param zoneId + * the ID of the zone + */ + public static AddSecondaryStorageOptions zoneId(long zoneId) { + return new AddSecondaryStorageOptions().zoneId(zoneId); + } + + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index acbba0beb9..8a29f37a75 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -26,6 +26,7 @@ import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.ConfigurationEntry; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.options.AddHostOptions; +import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.http.HttpRequest; @@ -210,6 +211,27 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, Long.valueOf(2036L)); } + @Test + public void testAddSecondaryStorageWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=addSecondaryStorage&url=nfs%3A%2F%2F10.26.26.165%2Fmnt%2Fnfs%2Fcs_sec&zoneid=1&apiKey=identity&signature=MccRKx1yPP43ImiO70WlhVDlAIA%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/addsecondarystorageresponse.json")) + .statusCode(200).build(); + + Date disconnected = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC"); + Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 42, 30, "UTC"); + Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "UTC"); + Host expected = Host.builder().id(2).name("nfs://10.26.26.165/mnt/nfs/cs_sec").state(Host.State.ALERT).disconnected(disconnected).type(Host.Type.SECONDARY_STORAGE).ipAddress("nfs").zoneId(1).zoneName("Dev Zone 1").version("2.2.12.20110928142833").hypervisor("None").lastPinged(lastPinged).localStorageActive(false).created(created).events("ManagementServerDown; AgentDisconnected; Remove; MaintenanceRequested; AgentConnected; Ping").hasEnoughCapacity(false).allocationState(Host.AllocationState.ENABLED).build(); + + Host actual = requestSendsResponse(request, response).addSecondaryStorage("nfs://10.26.26.165/mnt/nfs/cs_sec", AddSecondaryStorageOptions.Builder.zoneId(1)); + + assertEquals(actual, expected); + } + @Test public void testListClustersWhenResponseIs2xx() { HttpRequest request = HttpRequest.builder() diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptionsTest.java new file mode 100644 index 0000000000..3d9ca51ec7 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddSecondaryStorageOptionsTest.java @@ -0,0 +1,45 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableList; +import org.testng.annotations.Test; + +import static org.jclouds.cloudstack.options.AddSecondaryStorageOptions.Builder.*; +import static org.testng.Assert.assertEquals; + +/** + * Tests behavior of {@code AddSecondaryStorageOptions} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class AddSecondaryStorageOptionsTest { + + public void testZoneId() { + AddSecondaryStorageOptions options = new AddSecondaryStorageOptions().zoneId(6); + assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid")); + } + + public void testZoneIdStatic() { + AddSecondaryStorageOptions options = zoneId(6); + assertEquals(ImmutableList.of("6"), options.buildQueryParameters().get("zoneid")); + } + +} diff --git a/apis/cloudstack/src/test/resources/addsecondarystorageresponse.json b/apis/cloudstack/src/test/resources/addsecondarystorageresponse.json new file mode 100644 index 0000000000..d164d9a54c --- /dev/null +++ b/apis/cloudstack/src/test/resources/addsecondarystorageresponse.json @@ -0,0 +1,3 @@ +{ "addsecondarystorageresponse" : { "host" : + {"warning":"this test data is fabricated","id":2,"name":"nfs://10.26.26.165/mnt/nfs/cs_sec","state":"Alert","disconnected":"2011-11-26T23:33:38+0200","type":"SecondaryStorage","ipaddress":"nfs","zoneid":1,"zonename":"Dev Zone 1","version":"2.2.12.20110928142833","hypervisor":"None","lastpinged":"1970-01-16T00:42:30+0200","islocalstorageactive":false,"created":"2011-11-26T23:33:38+0200","events":"ManagementServerDown; AgentDisconnected; Remove; MaintenanceRequested; AgentConnected; Ping","hasEnoughCapacity":false,"allocationstate":"Enabled"}, +} } \ No newline at end of file From 47345053103b2082feef51a3c99930b781f9674f Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 15:25:41 +0200 Subject: [PATCH 29/82] Add GlobalHost[Async]Client.addCluster() --- .../features/GlobalHostAsyncClient.java | 17 +++ .../cloudstack/features/GlobalHostClient.java | 13 ++ .../cloudstack/options/AddClusterOptions.java | 115 ++++++++++++++++++ .../features/GlobalHostClientExpectTest.java | 19 +++ .../options/AddClusterOptionsTest.java | 86 +++++++++++++ .../test/resources/addclusterresponse.json | 1 + 6 files changed, 251 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddClusterOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddClusterOptionsTest.java create mode 100644 apis/cloudstack/src/test/resources/addclusterresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 9c46cd1367..9fde927dcb 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; import org.jclouds.cloudstack.filters.QuerySigner; +import org.jclouds.cloudstack.options.AddClusterOptions; import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; @@ -173,4 +174,20 @@ public interface GlobalHostAsyncClient { @Consumes(MediaType.APPLICATION_JSON) @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) ListenableFuture> listClusters(ListClustersOptions... options); + + /** + * Adds a new cluster. + * + * @param zoneId the Zone ID for the cluster + * @param clusterName the cluster name + * @param clusterType type of the cluster + * @param hypervisor hypervisor type of the cluster + * @param options optional arguments + * @return the new cluster. + */ + @GET + @QueryParams(keys = "command", values = "addCluster") + @SelectJson("cluster") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture addCluster(@QueryParam("zoneid") long zoneId, @QueryParam("clustername") String clusterName, @QueryParam("clustertype") Host.ClusterType clusterType, @QueryParam("hypervisor") String hypervisor, AddClusterOptions... options); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 77ae55e023..295b2d968e 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -20,6 +20,7 @@ package org.jclouds.cloudstack.features; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.Host; +import org.jclouds.cloudstack.options.AddClusterOptions; import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; @@ -131,4 +132,16 @@ public interface GlobalHostClient { * @return clusters matching query, or empty set if no clusters match */ Set listClusters(ListClustersOptions... options); + + /** + * Adds a new cluster. + * + * @param zoneId the Zone ID for the cluster + * @param clusterName the cluster name + * @param clusterType type of the cluster + * @param hypervisor hypervisor type of the cluster + * @param options optional arguments + * @return the new cluster. + */ + Cluster addCluster(long zoneId, String clusterName, Host.ClusterType clusterType, String hypervisor, AddClusterOptions... options); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddClusterOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddClusterOptions.java new file mode 100644 index 0000000000..107a6a8dcd --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/AddClusterOptions.java @@ -0,0 +1,115 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.domain.Host; +import org.jclouds.functions.JoinOnComma; +import org.jclouds.http.options.BaseHttpRequestOptions; + +import java.util.Set; + +/** + * Options to the GlobalHostClient.addHost() API call + * + * @author Richard Downer + */ +public class AddClusterOptions extends BaseHttpRequestOptions { + + public static final AddClusterOptions NONE = new AddClusterOptions(); + + /** + * @param allocationState Allocation state of this Host for allocation of new resources + */ + public AddClusterOptions allocationState(Host.AllocationState allocationState) { + this.queryParameters.replaceValues("allocationstate", ImmutableSet.of(allocationState.toString())); + return this; + } + + /** + * @param password the password for the host + */ + public AddClusterOptions password(String password) { + this.queryParameters.replaceValues("password", ImmutableSet.of(password)); + return this; + } + + /** + * @param podId the Pod ID for the host + */ + public AddClusterOptions podId(long podId) { + this.queryParameters.replaceValues("podid", ImmutableSet.of(podId + "")); + return this; + } + + /** + * @param url the URL + */ + public AddClusterOptions url(String url) { + this.queryParameters.replaceValues("url", ImmutableSet.of(url)); + return this; + } + + /** + * @param username the username for the cluster + */ + public AddClusterOptions username(String username) { + this.queryParameters.replaceValues("username", ImmutableSet.of(username)); + return this; + } + + public static class Builder { + + /** + * @param allocationState Allocation state of this Host for allocation of new resources + */ + public static AddClusterOptions allocationState(Host.AllocationState allocationState) { + return new AddClusterOptions().allocationState(allocationState); + } + + /** + * @param password the password for the host + */ + public static AddClusterOptions password(String password) { + return new AddClusterOptions().password(password); + } + + /** + * @param podId the Pod ID for the host + */ + public static AddClusterOptions podId(long podId) { + return new AddClusterOptions().podId(podId); + } + + /** + * @param url the URL + */ + public static AddClusterOptions url(String url) { + return new AddClusterOptions().url(url); + } + + /** + * @param username the username for the cluster + */ + public static AddClusterOptions username(String username) { + return new AddClusterOptions().username(username); + } + + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 8a29f37a75..0a00ec6f65 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -25,6 +25,7 @@ import org.jclouds.cloudstack.CloudStackContext; import org.jclouds.cloudstack.domain.Cluster; import org.jclouds.cloudstack.domain.ConfigurationEntry; import org.jclouds.cloudstack.domain.Host; +import org.jclouds.cloudstack.options.AddClusterOptions; import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; @@ -265,6 +266,24 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(client.listClusters(), ImmutableSet.of()); } + @Test + public void testAddClusterWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=addCluster&zoneid=1&clustertype=CloudManaged&clustername=Xen%20Clust%201&hypervisor=XenServer&allocationstate=Enabled&podid=1&url=http%3A%2F%2Fexample.com%2Fcluster&username=fred&password=sekrit&apiKey=identity&signature=2uIQ5qF0bVycXK111wxvogWp1Yw%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/addclusterresponse.json")) + .statusCode(200).build(); + + Cluster expected = Cluster.builder().id(1).name("Xen Clust 1").podId(1).podName("Dev Pod 1").zoneId(1).zoneName("Dev Zone 1").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build(); + + Cluster actual = requestSendsResponse(request, response).addCluster(1, "Xen Clust 1", Host.ClusterType.CLOUD_MANAGED, "XenServer", AddClusterOptions.Builder.allocationState(Host.AllocationState.ENABLED).podId(1).url("http://example.com/cluster").username("fred").password("sekrit")); + + assertEquals(actual, expected); + } + private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName)); cal.set(Calendar.YEAR, year); diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddClusterOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddClusterOptionsTest.java new file mode 100644 index 0000000000..333343eceb --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/AddClusterOptionsTest.java @@ -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.cloudstack.options; + +import com.google.common.collect.ImmutableList; +import org.jclouds.cloudstack.domain.Host; +import org.testng.annotations.Test; + +import static org.jclouds.cloudstack.options.AddClusterOptions.Builder.*; +import static org.testng.Assert.assertEquals; + +/** + * Tests behavior of {@code AddClusterOptions} + * + * @author Richard Downer + */ +@Test(groups = "unit") +public class AddClusterOptionsTest { + + public void testAllocationState() { + AddClusterOptions options = new AddClusterOptions().allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testAllocationStateStatic() { + AddClusterOptions options = allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testPassword() { + AddClusterOptions options = new AddClusterOptions().password("sekrit"); + assertEquals(ImmutableList.of("sekrit"), options.buildQueryParameters().get("password")); + } + + public void testPasswordStatic() { + AddClusterOptions options = password("sekrit"); + assertEquals(ImmutableList.of("sekrit"), options.buildQueryParameters().get("password")); + } + + public void testPodId() { + AddClusterOptions options = new AddClusterOptions().podId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid")); + } + + public void testPodIdStatic() { + AddClusterOptions options = podId(42L); + assertEquals(ImmutableList.of("42"), options.buildQueryParameters().get("podid")); + } + + public void testUrl() { + AddClusterOptions options = new AddClusterOptions().url("http://example.com"); + assertEquals(ImmutableList.of("http://example.com"), options.buildQueryParameters().get("url")); + } + + public void testUrlStatic() { + AddClusterOptions options = url("http://example.com"); + assertEquals(ImmutableList.of("http://example.com"), options.buildQueryParameters().get("url")); + } + + public void testUsername() { + AddClusterOptions options = new AddClusterOptions().username("fred"); + assertEquals(ImmutableList.of("fred"), options.buildQueryParameters().get("username")); + } + + public void testUsernameStatic() { + AddClusterOptions options = username("fred"); + assertEquals(ImmutableList.of("fred"), options.buildQueryParameters().get("username")); + } + +} diff --git a/apis/cloudstack/src/test/resources/addclusterresponse.json b/apis/cloudstack/src/test/resources/addclusterresponse.json new file mode 100644 index 0000000000..635a651f68 --- /dev/null +++ b/apis/cloudstack/src/test/resources/addclusterresponse.json @@ -0,0 +1 @@ +{ "addclusterresponse" : { "cluster" : {"warning":"this test data is fabricated","id":1,"name":"Xen Clust 1","podid":1,"podname":"Dev Pod 1","zoneid":1,"zonename":"Dev Zone 1","hypervisortype":"XenServer","clustertype":"CloudManaged","allocationstate":"Enabled","managedstate":"Managed"} } } \ No newline at end of file From fc50e80eb70f7f4323dc7c18140da60c701a28ff Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 15:33:39 +0200 Subject: [PATCH 30/82] Add GlobalHost[Async]Client.updateCluster() --- .../features/GlobalHostAsyncClient.java | 14 +++ .../cloudstack/features/GlobalHostClient.java | 10 ++ .../options/UpdateClusterOptions.java | 113 ++++++++++++++++++ .../features/GlobalHostClientExpectTest.java | 19 +++ .../options/UpdateClusterOptionsTest.java | 67 +++++++++++ .../test/resources/updateclusterresponse.json | 1 + 6 files changed, 224 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateClusterOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateClusterOptionsTest.java create mode 100644 apis/cloudstack/src/test/resources/updateclusterresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 9fde927dcb..2f7da209bf 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -28,6 +28,7 @@ import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; +import org.jclouds.cloudstack.options.UpdateClusterOptions; import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.QueryParams; @@ -190,4 +191,17 @@ public interface GlobalHostAsyncClient { @SelectJson("cluster") @Consumes(MediaType.APPLICATION_JSON) ListenableFuture addCluster(@QueryParam("zoneid") long zoneId, @QueryParam("clustername") String clusterName, @QueryParam("clustertype") Host.ClusterType clusterType, @QueryParam("hypervisor") String hypervisor, AddClusterOptions... options); + + /** + * Updates an existing cluster. + * + * @param clusterId the ID of the cluster + * @param options optional arguments + * @return the modified cluster + */ + @GET + @QueryParams(keys = "command", values = "updateCluster") + @SelectJson("cluster") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture updateCluster(@QueryParam("id") long clusterId, UpdateClusterOptions... options); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 295b2d968e..24cb3e9000 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -26,6 +26,7 @@ import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; import org.jclouds.cloudstack.options.ListClustersOptions; import org.jclouds.cloudstack.options.ListHostsOptions; +import org.jclouds.cloudstack.options.UpdateClusterOptions; import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.concurrent.Timeout; @@ -144,4 +145,13 @@ public interface GlobalHostClient { * @return the new cluster. */ Cluster addCluster(long zoneId, String clusterName, Host.ClusterType clusterType, String hypervisor, AddClusterOptions... options); + + /** + * Updates an existing cluster. + * + * @param clusterId the ID of the cluster + * @param options optional arguments + * @return the modified cluster + */ + Cluster updateCluster(long clusterId, UpdateClusterOptions... options); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateClusterOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateClusterOptions.java new file mode 100644 index 0000000000..e02fcbdb51 --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateClusterOptions.java @@ -0,0 +1,113 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.domain.Cluster; +import org.jclouds.cloudstack.domain.Host; +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Options for the GlobalHostClient.updateCluster() API call. + * + * @author Richard Downer + */ +public class UpdateClusterOptions extends BaseHttpRequestOptions { + + public static final UpdateClusterOptions NONE = new UpdateClusterOptions(); + + /** + * @param allocationState Allocation state of this cluster for allocation of new resources + */ + public UpdateClusterOptions allocationState(Host.AllocationState allocationState) { + this.queryParameters.replaceValues("allocationstate", ImmutableSet.of(allocationState.toString())); + return this; + } + + /** + * @param clusterName the cluster name + */ + public UpdateClusterOptions clusterName(String clusterName) { + this.queryParameters.replaceValues("clustername", ImmutableSet.of(clusterName)); + return this; + } + + /** + * @param clusterType type of the cluster + */ + public UpdateClusterOptions clusterType(Host.ClusterType clusterType) { + this.queryParameters.replaceValues("clustertype", ImmutableSet.of(clusterType.toString())); + return this; + } + + /** + * @param hypervisor hypervisor type of the cluster + */ + public UpdateClusterOptions hypervisor(String hypervisor) { + this.queryParameters.replaceValues("hypervisor", ImmutableSet.of(hypervisor)); + return this; + } + + /** + * @param managedState whether this cluster is managed by cloudstack + */ + public UpdateClusterOptions managedState(Cluster.ManagedState managedState) { + this.queryParameters.replaceValues("managedstate", ImmutableSet.of(managedState.toString())); + return this; + } + + public static class Builder { + + /** + * @param allocationState Allocation state of this cluster for allocation of new resources + */ + public static UpdateClusterOptions allocationState(Host.AllocationState allocationState) { + return new UpdateClusterOptions().allocationState(allocationState); + } + + /** + * @param clusterName the cluster name + */ + public static UpdateClusterOptions clusterName(String clusterName) { + return new UpdateClusterOptions().clusterName(clusterName); + } + + /** + * @param clusterType type of the cluster + */ + public static UpdateClusterOptions clusterType(Host.ClusterType clusterType) { + return new UpdateClusterOptions().clusterType(clusterType); + } + + /** + * @param hypervisor hypervisor type of the cluster + */ + public static UpdateClusterOptions hypervisor(String hypervisor) { + return new UpdateClusterOptions().hypervisor(hypervisor); + } + + /** + * @param managedState whether this cluster is managed by cloudstack + */ + public static UpdateClusterOptions managedState(Cluster.ManagedState managedState) { + return new UpdateClusterOptions().managedState(managedState); + } + + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 0a00ec6f65..b4df927fb0 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -29,6 +29,7 @@ import org.jclouds.cloudstack.options.AddClusterOptions; import org.jclouds.cloudstack.options.AddHostOptions; import org.jclouds.cloudstack.options.AddSecondaryStorageOptions; import org.jclouds.cloudstack.options.DeleteHostOptions; +import org.jclouds.cloudstack.options.UpdateClusterOptions; import org.jclouds.cloudstack.options.UpdateHostOptions; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; @@ -284,6 +285,24 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, expected); } + @Test + public void testUpdateClusterWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateCluster&id=1&allocationstate=Enabled&clustername=Xen%20Clust%201&clustertype=CloudManaged&hypervisor=XenServer&managedstate=Managed&apiKey=identity&signature=%2FwbuYKwInciSXWkUf05lEfJZShQ%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .payload(payloadFromResource("/updateclusterresponse.json")) + .statusCode(200).build(); + + Cluster expected = Cluster.builder().id(1).name("Xen Clust 1").podId(1).podName("Dev Pod 1").zoneId(1).zoneName("Dev Zone 1").hypervisor("XenServer").clusterType(Host.ClusterType.CLOUD_MANAGED).allocationState(Host.AllocationState.ENABLED).managedState(Cluster.ManagedState.MANAGED).build(); + + Cluster actual = requestSendsResponse(request, response).updateCluster(1, UpdateClusterOptions.Builder.allocationState(Host.AllocationState.ENABLED).clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).hypervisor("XenServer").managedState(Cluster.ManagedState.MANAGED)); + + assertEquals(actual, expected); + } + private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName)); cal.set(Calendar.YEAR, year); diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateClusterOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateClusterOptionsTest.java new file mode 100644 index 0000000000..0cb7db39e1 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/UpdateClusterOptionsTest.java @@ -0,0 +1,67 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableList; +import org.jclouds.cloudstack.domain.Cluster; +import org.jclouds.cloudstack.domain.Host; +import org.testng.annotations.Test; + +import static org.jclouds.cloudstack.options.UpdateClusterOptions.Builder.allocationState; +import static org.testng.Assert.assertEquals; + +/** + * Tests behavior of {@code UpdateClusterOptions} + * + * @author Richard Downer + */ +@Test(groups = "unit") +public class UpdateClusterOptionsTest { + + public void testAllocationState() { + UpdateClusterOptions options = new UpdateClusterOptions().allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testAllocationStateStatic() { + UpdateClusterOptions options = allocationState(Host.AllocationState.ENABLED); + assertEquals(ImmutableList.of("Enabled"), options.buildQueryParameters().get("allocationstate")); + } + + public void testClusterName() { + UpdateClusterOptions options = new UpdateClusterOptions().clusterName("My Cluster"); + assertEquals(ImmutableList.of("My Cluster"), options.buildQueryParameters().get("clustername")); + } + + public void testClusterType() { + UpdateClusterOptions options = new UpdateClusterOptions().clusterType(Host.ClusterType.CLOUD_MANAGED); + assertEquals(ImmutableList.of("CloudManaged"), options.buildQueryParameters().get("clustertype")); + } + + public void testHypervisor() { + UpdateClusterOptions options = new UpdateClusterOptions().hypervisor("XenServer"); + assertEquals(ImmutableList.of("XenServer"), options.buildQueryParameters().get("hypervisor")); + } + + public void testManagedState() { + UpdateClusterOptions options = new UpdateClusterOptions().managedState(Cluster.ManagedState.PREPARE_UNMANAGED); + assertEquals(ImmutableList.of("PrepareUnmanaged"), options.buildQueryParameters().get("managedstate")); + } + +} diff --git a/apis/cloudstack/src/test/resources/updateclusterresponse.json b/apis/cloudstack/src/test/resources/updateclusterresponse.json new file mode 100644 index 0000000000..4a03ca3a25 --- /dev/null +++ b/apis/cloudstack/src/test/resources/updateclusterresponse.json @@ -0,0 +1 @@ +{ "updateclusterresponse" : { "cluster" : {"warning":"this test data is fabricated","id":1,"name":"Xen Clust 1","podid":1,"podname":"Dev Pod 1","zoneid":1,"zonename":"Dev Zone 1","hypervisortype":"XenServer","clustertype":"CloudManaged","allocationstate":"Enabled","managedstate":"Managed"} } } \ No newline at end of file From 7284d7db2f80c61930bfd2910274125b37d5868d Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 15:36:14 +0200 Subject: [PATCH 31/82] Add GlobalHost[Async]Client.updateClusterPassword() --- .../cloudstack/features/GlobalHostAsyncClient.java | 13 +++++++++++++ .../cloudstack/features/GlobalHostClient.java | 9 +++++++++ .../features/GlobalHostClientExpectTest.java | 13 +++++++++++++ 3 files changed, 35 insertions(+) diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index 2f7da209bf..be0c3a9a79 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -204,4 +204,17 @@ public interface GlobalHostAsyncClient { @SelectJson("cluster") @Consumes(MediaType.APPLICATION_JSON) ListenableFuture updateCluster(@QueryParam("id") long clusterId, UpdateClusterOptions... options); + + /** + * Update password of a cluster on management server. + * + * @param clusterId the cluster ID + * @param username the username for the cluster + * @param password the password for the cluster + */ + @GET + @QueryParams(keys = "command", values = "updateHostPassword") + @SelectJson("cluster") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture updateClusterPassword(@QueryParam("clusterid") long clusterId, @QueryParam("username") String username, @QueryParam("password") String password); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index 24cb3e9000..f1b042ef53 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -154,4 +154,13 @@ public interface GlobalHostClient { * @return the modified cluster */ Cluster updateCluster(long clusterId, UpdateClusterOptions... options); + + /** + * Update password of a cluster on management server. + * + * @param hostId the cluster ID + * @param username the username for the cluster + * @param password the password for the cluster + */ + void updateClusterPassword(long clusterId, String username, String password); } diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index b4df927fb0..57b0a7414f 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -303,6 +303,19 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe assertEquals(actual, expected); } + @Test + public void testUpdateClusterPasswordWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=updateHostPassword&clusterid=1&password=sekrit&username=fred&apiKey=identity&signature=xwc83%2BoYK0cuAiFQAlg%2F7%2F1IVHE%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .statusCode(200).build(); + + requestSendsResponse(request, response).updateClusterPassword(1, "fred", "sekrit"); + } + private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName)); cal.set(Calendar.YEAR, year); From 17fb7b55d036772932206d641e5464e03a31e109 Mon Sep 17 00:00:00 2001 From: Richard Downer Date: Thu, 12 Jan 2012 15:38:45 +0200 Subject: [PATCH 32/82] Add GlobalHost[Async]Client.deleteCluster() --- .../cloudstack/features/GlobalHostAsyncClient.java | 11 +++++++++++ .../cloudstack/features/GlobalHostClient.java | 8 ++++++++ .../features/GlobalHostClientExpectTest.java | 13 +++++++++++++ 3 files changed, 32 insertions(+) diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java index be0c3a9a79..7085302d30 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostAsyncClient.java @@ -217,4 +217,15 @@ public interface GlobalHostAsyncClient { @SelectJson("cluster") @Consumes(MediaType.APPLICATION_JSON) ListenableFuture updateClusterPassword(@QueryParam("clusterid") long clusterId, @QueryParam("username") String username, @QueryParam("password") String password); + + /** + * Deletes a cluster. + * + * @param clusterId the cluster ID + */ + @GET + @QueryParams(keys = "command", values = "deleteCluster") + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture deleteCluster(@QueryParam("id") long clusterId); + } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java index f1b042ef53..7345263990 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalHostClient.java @@ -163,4 +163,12 @@ public interface GlobalHostClient { * @param password the password for the cluster */ void updateClusterPassword(long clusterId, String username, String password); + + /** + * Deletes a cluster. + * + * @param clusterId the cluster ID + */ + void deleteCluster(long clusterId); + } diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java index 57b0a7414f..616b135a5e 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java @@ -316,6 +316,19 @@ public class GlobalHostClientExpectTest extends BaseCloudStackRestClientExpectTe requestSendsResponse(request, response).updateClusterPassword(1, "fred", "sekrit"); } + @Test + public void testDeleteClusterWhenResponseIs2xx() { + HttpRequest request = HttpRequest.builder() + .method("GET") + .endpoint(URI.create("http://localhost:8080/client/api?response=json&command=deleteCluster&id=1&apiKey=identity&signature=CKH26MFgKGY7Sosd17LjBMNa3AI%3D")) + .headers(ImmutableMultimap.builder().put("Accept", "application/json").build()) + .build(); + HttpResponse response = HttpResponse.builder() + .statusCode(200).build(); + + requestSendsResponse(request, response).deleteCluster(1); + } + private Date makeDate(int year, int month, int date, int hour, int minute, int second, String timeZoneName) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneName)); cal.set(Calendar.YEAR, year); From f363771464bde53290541cd89c0f4c9ab8369393 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 17:59:50 -0800 Subject: [PATCH 33/82] os tidies --- .../java/org/jclouds/compute/domain/CIMOperatingSystem.java | 4 ++-- .../main/java/org/jclouds/compute/domain/OperatingSystem.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java b/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java index 51c2503fbf..54b9936326 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java +++ b/compute/src/main/java/org/jclouds/compute/domain/CIMOperatingSystem.java @@ -177,7 +177,7 @@ public class CIMOperatingSystem extends OperatingSystem { @Override public String toString() { - return String.format("[osType=%s, arch=%s, description=%s, family=%s, is64Bit=%s, name=%s, version=%s]", osType, - arch, description, family, is64Bit, name, version); + return "[name=" + name + ", family=" + family + ", version=" + version + ", arch=" + arch + ", is64Bit=" + + is64Bit + ", description=" + description + ", osType=" + osType+ "]"; } } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java b/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java index a5a02546d7..8135675c13 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java +++ b/compute/src/main/java/org/jclouds/compute/domain/OperatingSystem.java @@ -211,7 +211,7 @@ public class OperatingSystem { return true; if (obj == null) return false; - if (getClass() != obj.getClass()) + if (!(obj instanceof OperatingSystem)) return false; OperatingSystem other = (OperatingSystem) obj; if (arch == null) { From 091ee3118cab43be4c59f6c01261ba1a120d7cd7 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 18:00:12 -0800 Subject: [PATCH 34/82] changed mirror for test binary file --- project/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/pom.xml b/project/pom.xml index 2f5cde13c8..80c8027cd3 100644 --- a/project/pom.xml +++ b/project/pom.xml @@ -194,7 +194,7 @@ gitsite:git@github.com/jclouds/jclouds-maven-site.git - http://apache.opensourceresources.org/commons/logging/binaries/commons-logging-1.1.1-bin.tar.gz + http://apache.opensourceresources.org//commons/logging/binaries/commons-logging-1.1.1-bin.tar.gz e5de09672af9b386c30a311654d8541a ${jclouds.wire.httpstream.url} ${jclouds.wire.httpstream.md5} From 983b1fbe0710dd57ab55b133dcfeefbcf98e4ce6 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 18:00:36 -0800 Subject: [PATCH 35/82] fixed bad pom entry on live profile --- apis/nova/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apis/nova/pom.xml b/apis/nova/pom.xml index 8699579abb..490f6dc474 100644 --- a/apis/nova/pom.xml +++ b/apis/nova/pom.xml @@ -100,12 +100,6 @@ org.apache.maven.plugins maven-surefire-plugin - - - org.apache.maven.surefire - surefire-testng - - integration From 5039708d34ccfc1592de03b8b1f66f231898fbf8 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 18:02:34 -0800 Subject: [PATCH 36/82] now with guice in production mode, we get exceptions wrapped in CreationException and need to unwrap these accordingly --- .../java/org/jclouds/util/Throwables2.java | 19 +++++++ .../org/jclouds/util/Throwables2Test.java | 53 ++++++++++++++++--- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/jclouds/util/Throwables2.java b/core/src/main/java/org/jclouds/util/Throwables2.java index 559dfe74f7..00fa94d2f4 100644 --- a/core/src/main/java/org/jclouds/util/Throwables2.java +++ b/core/src/main/java/org/jclouds/util/Throwables2.java @@ -31,6 +31,7 @@ import org.jclouds.rest.InsufficientResourcesException; import org.jclouds.rest.ResourceNotFoundException; import com.google.common.base.Throwables; +import com.google.inject.CreationException; import com.google.inject.ProvisionException; import com.google.inject.spi.Message; @@ -45,6 +46,8 @@ public class Throwables2 { public static T getFirstThrowableOfType(Throwable from, Class clazz) { if (from instanceof ProvisionException) return getFirstThrowableOfType(ProvisionException.class.cast(from), clazz); + else if (from instanceof CreationException) + return getFirstThrowableOfType(CreationException.class.cast(from), clazz); try { return (T) find(getCausalChain(from), instanceOf(clazz)); } catch (NoSuchElementException e) { @@ -58,6 +61,22 @@ public class Throwables2 { T cause = getFirstThrowableOfType(message.getCause(), clazz); if (cause instanceof ProvisionException) return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz); + else if (cause instanceof CreationException) + return getFirstThrowableOfType(CreationException.class.cast(cause), clazz); + return cause; + } + } + return null; + } + + public static T getFirstThrowableOfType(CreationException e, Class clazz) { + for (Message message : e.getErrorMessages()) { + if (message.getCause() != null) { + T cause = getFirstThrowableOfType(message.getCause(), clazz); + if (cause instanceof ProvisionException) + return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz); + else if (cause instanceof CreationException) + return getFirstThrowableOfType(CreationException.class.cast(cause), clazz); return cause; } } diff --git a/core/src/test/java/org/jclouds/util/Throwables2Test.java b/core/src/test/java/org/jclouds/util/Throwables2Test.java index ecc89b9a9c..20110ebb4a 100644 --- a/core/src/test/java/org/jclouds/util/Throwables2Test.java +++ b/core/src/test/java/org/jclouds/util/Throwables2Test.java @@ -18,8 +18,8 @@ */ package org.jclouds.util; -import static org.easymock.classextension.EasyMock.createMock; -import static org.easymock.classextension.EasyMock.createNiceMock; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createNiceMock; import static org.jclouds.util.Throwables2.getFirstThrowableOfType; import static org.jclouds.util.Throwables2.returnFirstExceptionIfInListOrThrowStandardExceptionOrCause; import static org.testng.Assert.assertEquals; @@ -37,6 +37,7 @@ import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.inject.CreationException; import com.google.inject.ProvisionException; import com.google.inject.spi.Message; @@ -46,12 +47,6 @@ import com.google.inject.spi.Message; @Test public class Throwables2Test { - public void testGetCause() { - AuthorizationException aex = createMock(AuthorizationException.class); - Message message = new Message(ImmutableList.of(), "test", aex); - ProvisionException pex = new ProvisionException(ImmutableSet.of(message)); - assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex); - } public void testGetFirstThrowableOfTypeSubclass() { SocketException aex = createMock(SocketException.class); @@ -62,6 +57,13 @@ public class Throwables2Test { AuthorizationException aex = createMock(AuthorizationException.class); assertEquals(getFirstThrowableOfType(aex, AuthorizationException.class), aex); } + + public void testGetCause() { + AuthorizationException aex = createMock(AuthorizationException.class); + Message message = new Message(ImmutableList.of(), "test", aex); + ProvisionException pex = new ProvisionException(ImmutableSet.of(message)); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex); + } public void testGetFirstThrowableOfTypeInner() { AuthorizationException aex = createMock(AuthorizationException.class); @@ -83,6 +85,34 @@ public class Throwables2Test { assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null); } + + public void testGetCauseCreation() { + AuthorizationException aex = createMock(AuthorizationException.class); + Message message = new Message(ImmutableList.of(), "test", aex); + CreationException pex = new CreationException(ImmutableSet.of(message)); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex); + } + + public void testGetFirstThrowableOfTypeInnerCreation() { + AuthorizationException aex = createMock(AuthorizationException.class); + Message message = new Message(ImmutableList.of(), "test", aex); + CreationException pex = new CreationException(ImmutableSet.of(message)); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex); + } + + public void testGetFirstThrowableOfTypeFailCreation() { + TimeoutException aex = createMock(TimeoutException.class); + Message message = new Message(ImmutableList.of(), "test", aex); + CreationException pex = new CreationException(ImmutableSet.of(message)); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null); + } + + public void testGetFirstThrowableOfTypeWhenCauseIsNullCreation() { + Message message = new Message(ImmutableList.of(), "test", null); + CreationException pex = new CreationException(ImmutableSet.of(message)); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null); + } + @Test public void testReturnExceptionThatsInList() throws Exception { Exception e = new TestException(); @@ -135,6 +165,13 @@ public class Throwables2Test { ImmutableList.of(), "Error in custom provider",e)))); } + @Test(expectedExceptions = AuthorizationException.class) + public void testPropagateCreationExceptionAuthorizationException() throws Exception { + Exception e = new AuthorizationException(); + returnFirstExceptionIfInListOrThrowStandardExceptionOrCause(new Class[] {}, new CreationException(ImmutableSet.of(new Message( + ImmutableList.of(), "Error in custom provider",e)))); + } + @Test(expectedExceptions = InsufficientResourcesException.class) public void testPropagateStandardExceptionInsufficientResourcesException() throws Exception { Exception e = new InsufficientResourcesException(); From 912635e454ebc9ea5939573f37bc1cf81f6c6893 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 18:03:39 -0800 Subject: [PATCH 37/82] authorization exception is now gone --- .../jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java b/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java index 019255519e..44e4d6fba7 100644 --- a/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java +++ b/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java @@ -151,7 +151,7 @@ public class RetryOnRenewExpectTest extends BaseCloudServersRestClientExpectTest } // FIXME stack trace shows the AuthorizationException, but it's buried inside a guice TestException - @Test(enabled=false, expectedExceptions=AuthorizationException.class) + @Test(expectedExceptions=AuthorizationException.class) public void testDoesNotReauthenticateOnAuthentication401() { HttpRequest initialAuth = HttpRequest.builder().method("GET").endpoint(URI.create("https://auth/v1.0")) .headers( @@ -166,7 +166,7 @@ public class RetryOnRenewExpectTest extends BaseCloudServersRestClientExpectTest .payload(Payloads.newStringPayload("[{\"unauthorized\":{\"message\":\"A different message implying fatal.\",\"code\":401}}]")) .build(); - CloudServersClient client = orderedRequestsSendResponses(initialAuth, unauthResponse); + CloudServersClient client = requestSendsResponse(initialAuth, unauthResponse); client.deleteImage(11); } From ef7e0a46e2140803fe650d0db19b3479c108f605 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 18:04:19 -0800 Subject: [PATCH 38/82] refactored expect tests to throw a 'server error' when there's no state expectation configured --- .../rest/BaseRestClientExpectTest.java | 69 +++++++++++++------ .../VirtualGuestClientExpectTest.java | 4 +- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java b/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java index 61b54f2796..ad8dca8a08 100644 --- a/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java +++ b/core/src/test/java/org/jclouds/rest/BaseRestClientExpectTest.java @@ -23,14 +23,15 @@ import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import static org.jclouds.rest.RestContextFactory.contextSpec; import static org.jclouds.rest.RestContextFactory.createContext; +import static org.testng.Assert.assertEquals; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Properties; +import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; @@ -60,8 +61,8 @@ import org.testng.annotations.Test; import com.google.common.annotations.Beta; import com.google.common.base.Function; -import com.google.common.base.Functions; import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -146,6 +147,18 @@ public abstract class BaseRestClientExpectTest { return Payloads.newInputStreamPayload(getClass().getResourceAsStream(resource)); } + public Payload payloadFromResourceWithContentType(String resource, String contentType) { + try { + Payload payload = Payloads.newStringPayload(Strings2 + .toStringAndClose(getClass().getResourceAsStream(resource))); + payload.getContentMetadata().setContentType(contentType); + return payload; + } catch (IOException e) { + throw Throwables.propagate(e); + } + + } + /** * Mock executor service which uses the supplied function to return http responses. */ @@ -214,11 +227,11 @@ public abstract class BaseRestClientExpectTest { public S requestSendsResponse(HttpRequest request, HttpResponse response) { return requestSendsResponse(request, response, createModule()); } - + public S requestSendsResponse(HttpRequest request, HttpResponse response, Module module) { return requestsSendResponses(ImmutableMap.of(request, response), module); } - + /** * creates a client for a mock server which only responds to two types of requests * @@ -263,14 +276,11 @@ public abstract class BaseRestClientExpectTest { HttpResponse responseB, HttpRequest requestC, HttpResponse responseC) { return requestsSendResponses(requestA, responseA, requestB, responseB, requestC, responseC, createModule()); } - + public S requestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB, HttpResponse responseB, HttpRequest requestC, HttpResponse responseC, Module module) { - return requestsSendResponses(ImmutableMap.of(requestA, responseA, requestB, responseB, requestC, responseC), module); - } - - public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA) { - return orderedRequestsSendResponses(ImmutableList.of(requestA), ImmutableList.of(responseA)); + return requestsSendResponses(ImmutableMap.of(requestA, responseA, requestB, responseB, requestC, responseC), + module); } public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB, @@ -280,25 +290,29 @@ public abstract class BaseRestClientExpectTest { public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB, HttpResponse responseB, HttpRequest requestC, HttpResponse responseC) { - return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC), ImmutableList.of(responseA, responseB, responseC)); + return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC), ImmutableList.of(responseA, + responseB, responseC)); } public S orderedRequestsSendResponses(HttpRequest requestA, HttpResponse responseA, HttpRequest requestB, - HttpResponse responseB, HttpRequest requestC, HttpResponse responseC, HttpRequest requestD, HttpResponse responseD) { - return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC, requestD), ImmutableList.of(responseA, responseB, responseC, responseD)); + HttpResponse responseB, HttpRequest requestC, HttpResponse responseC, HttpRequest requestD, + HttpResponse responseD) { + return orderedRequestsSendResponses(ImmutableList.of(requestA, requestB, requestC, requestD), ImmutableList.of( + responseA, responseB, responseC, responseD)); } public S orderedRequestsSendResponses(final List requests, final List responses) { final AtomicInteger counter = new AtomicInteger(0); - - return createClient(new Function() { + + return createClient(new Function() { @Override public HttpResponse apply(HttpRequest input) { int index = counter.getAndIncrement(); - if (index >= requests.size()) { - throw new IndexOutOfBoundsException("request index "+index+", but only "+requests.size()+" request/response pairs"); - } - assert input.equals(requests.get(index)) : "expected="+requests.get(index)+"; actual="+input; + if (index >= requests.size()) + return HttpResponse.builder().statusCode(500).message( + String.format("request %s is out of range (%s)", index, requests.size())).payload( + Payloads.newStringPayload(renderRequest(input))).build(); + assertEquals(renderRequest(input), renderRequest(requests.get(index))); return responses.get(index); } }); @@ -316,8 +330,21 @@ public abstract class BaseRestClientExpectTest { return requestsSendResponses(requestToResponse, createModule()); } - public S requestsSendResponses(Map requestToResponse, Module module) { - return createClient(Functions.forMap(requestToResponse), module); + public S requestsSendResponses(final Map requestToResponse, Module module) { + return createClient(new Function() { + ImmutableBiMap bimap = ImmutableBiMap.copyOf(requestToResponse); + + @Override + public HttpResponse apply(HttpRequest input) { + if (!(requestToResponse.containsKey(input))) + return HttpResponse.builder().statusCode(500).message("no response configured for request").payload( + Payloads.newStringPayload(renderRequest(input))).build(); + HttpResponse response = requestToResponse.get(input); + // in case hashCode/equals doesn't do a full content check + assertEquals(renderRequest(input), renderRequest(bimap.inverse().get(response))); + return response; + } + }, module); } public String renderRequest(HttpRequest request) { diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java index d4c8124891..a6eb5eb469 100644 --- a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java +++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/VirtualGuestClientExpectTest.java @@ -46,8 +46,8 @@ public class VirtualGuestClientExpectTest extends BaseRestClientExpectTest builder() - .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==") - .put("Accept", "application/json").build()).build(); + .put("Accept", "application/json") + .put("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build()).build(); HttpResponse found = HttpResponse.builder().statusCode(200).build(); From 260c23170b8de571850970ab6f170f42a428ac7e Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 19:04:12 -0800 Subject: [PATCH 39/82] Issue 710:customize is not supported on vCloud 1.0 --- ...antiateVAppTemplateParamsToXmlPayload.java | 17 +------ ...IntoNameThenCustomizeDeployAndPowerOn.java | 1 - .../InstantiateVAppTemplateOptions.java | 23 +--------- ...ateVAppTemplateParamsToXmlPayloadTest.java | 45 ++----------------- .../InstantiateVAppTemplateOptionsTest.java | 14 ------ .../instantiationparams-customization.xml | 1 - 6 files changed, 6 insertions(+), 95 deletions(-) delete mode 100644 apis/vcloud/src/test/resources/instantiationparams-customization.xml diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java index 984d5bf6ce..9c531a9769 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java @@ -101,7 +101,6 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder boolean deploy = true; boolean powerOn = true; - Boolean customizeOnInstantiate = null; Set networkConfig = null; @@ -116,7 +115,6 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder networknetworkConfigDecorator)); deploy = ifNullDefaultTo(options.shouldDeploy(), deploy); powerOn = ifNullDefaultTo(options.shouldPowerOn(), powerOn); - customizeOnInstantiate = options.shouldCustomizeOnInstantiate(); } if (networkConfig == null) @@ -125,8 +123,7 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder try { return stringBinder.bindToRequest( request, - generateXml(name, options.getDescription(), deploy, powerOn, template, networkConfig, - customizeOnInstantiate)); + generateXml(name, options.getDescription(), deploy, powerOn, template, networkConfig)); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } catch (FactoryConfigurationError e) { @@ -202,14 +199,13 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder } protected String generateXml(String name, @Nullable String description, boolean deploy, boolean powerOn, - URI template, Iterable networkConfig, @Nullable Boolean customizeOnInstantiate) + URI template, Iterable networkConfig) throws ParserConfigurationException, FactoryConfigurationError, TransformerException { XMLBuilder rootBuilder = buildRoot(name).a("deploy", deploy + "").a("powerOn", powerOn + ""); if (description != null) rootBuilder.e("Description").t(description); XMLBuilder instantiationParamsBuilder = rootBuilder.e("InstantiationParams"); addNetworkConfig(instantiationParamsBuilder, networkConfig); - addCustomizationConfig(instantiationParamsBuilder, customizeOnInstantiate); rootBuilder.e("Source").a("href", template.toASCIIString()); rootBuilder.e("AllEULAsAccepted").t("true"); @@ -218,15 +214,6 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder return rootBuilder.asString(outputProperties); } - protected void addCustomizationConfig(XMLBuilder instantiationParamsBuilder, Boolean customizeOnInstantiate) { - if (customizeOnInstantiate != null) { - // XMLBuilder customizationSectionBuilder = - // instantiationParamsBuilder.e("CustomizationSection"); - // customizationSectionBuilder.e("ovf:Info").t("VApp template customization section"); - // customizationSectionBuilder.e("CustomizeOnInstantiate").t(customizeOnInstantiate.toString()); - } - } - protected void addNetworkConfig(XMLBuilder instantiationParamsBuilder, Iterable networkConfig) { XMLBuilder networkConfigBuilder = instantiationParamsBuilder.e("NetworkConfigSection"); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java index 6bb0948769..e98b88dbc1 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java @@ -79,7 +79,6 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA .getIpAddressAllocationMode(); options.description(VCloudTemplateOptions.class.cast(template.getOptions()).getDescription()); - options.customizeOnInstantiate(false); options.deploy(false); options.powerOn(false); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java index 3be4d56f60..6212e5ddc7 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java @@ -88,16 +88,7 @@ public class InstantiateVAppTemplateOptions { this.block = block; return this; } - - /** - * If true, then customization is executed for all children that include a - * GuestCustomizationSection. - */ - public InstantiateVAppTemplateOptions customizeOnInstantiate(boolean customizeOnInstantiate) { - this.customizeOnInstantiate = customizeOnInstantiate; - return this; - } - + /** * {@networkConfig VAppTemplate}s have internal networks that can be * connected in order to access the internet or other external networks. @@ -123,10 +114,6 @@ public class InstantiateVAppTemplateOptions { return networkConfig; } - public Boolean shouldCustomizeOnInstantiate() { - return customizeOnInstantiate; - } - public static class Builder { /** @@ -161,14 +148,6 @@ public class InstantiateVAppTemplateOptions { return options.powerOn(powerOn); } - /** - * @see InstantiateVAppTemplateOptions#customizeOnInstantiate - */ - public static InstantiateVAppTemplateOptions customizeOnInstantiate(Boolean customizeOnInstantiate) { - InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); - return options.customizeOnInstantiate(customizeOnInstantiate); - } - /** * @see InstantiateVAppTemplateOptions#addNetworkConfig */ diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java index c6dad9bc06..0aa1667708 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java @@ -19,12 +19,11 @@ package org.jclouds.vcloud.binders; import static com.google.common.base.Preconditions.checkNotNull; +import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; -import static org.easymock.classextension.EasyMock.createMock; -import static org.easymock.classextension.EasyMock.replay; -import static org.easymock.classextension.EasyMock.verify; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig; -import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.customizeOnInstantiate; import java.io.IOException; import java.net.URI; @@ -235,42 +234,4 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { binder.bindToRequest(request, map); verify(request); } - - public void testWithCustomization() throws IOException { - - URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); - VAppTemplate template = createMock(VAppTemplate.class); - VCloudNetworkSection net = createMock(VCloudNetworkSection.class); - InstantiateVAppTemplateOptions options = customizeOnInstantiate(true); - - String expected = Strings2.toStringAndClose(getClass().getResourceAsStream( - "/instantiationparams-customization.xml")); - - GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); - expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); - expect(request.getArgs()).andReturn(ImmutableList. of(options)).atLeastOnce(); - request.setPayload(expected); - - expect(template.getNetworkSection()).andReturn(net).atLeastOnce(); - expect(net.getNetworks()).andReturn( - ImmutableSet. of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null))); - - replay(request); - replay(template); - replay(net); - - BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); - - Map map = Maps.newHashMap(); - map.put("name", "my-vapp"); - map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); - - binder.bindToRequest(request, map); - - verify(request); - verify(template); - verify(net); - - } } diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java index 1971f316c0..e8b4943891 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptionsTest.java @@ -19,7 +19,6 @@ package org.jclouds.vcloud.options; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig; -import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.customizeOnInstantiate; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.description; import static org.testng.Assert.assertEquals; @@ -62,19 +61,6 @@ public class InstantiateVAppTemplateOptionsTest { assertEquals(Iterables.get(options.getNetworkConfig(), 0).getFenceMode(), FenceMode.BRIDGED); } - @Test - public void testCustomizeOnInstantiate() { - InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); - options.customizeOnInstantiate(true); - assertEquals(options.shouldCustomizeOnInstantiate(), new Boolean(true)); - } - - @Test - public void testCustomizeOnInstantiateStatic() { - InstantiateVAppTemplateOptions options = customizeOnInstantiate(true); - assertEquals(options.shouldCustomizeOnInstantiate(), new Boolean(true)); - } - @Test public void testDescription() { InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); diff --git a/apis/vcloud/src/test/resources/instantiationparams-customization.xml b/apis/vcloud/src/test/resources/instantiationparams-customization.xml deleted file mode 100644 index 9df99619b8..0000000000 --- a/apis/vcloud/src/test/resources/instantiationparams-customization.xml +++ /dev/null @@ -1 +0,0 @@ -Configuration parameters for logical networksbridgedtrue \ No newline at end of file From 61f2ff64681a94637ca7dd6fba018c6dccc851a2 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 19:06:06 -0800 Subject: [PATCH 40/82] vcloud director 1.5 adds suffix of ;1.0 on content type --- .../handlers/ParseVCloudErrorFromHttpResponse.java | 12 +++++------- .../java/org/jclouds/vcloud/util/VCloudUtils.java | 5 ++++- .../ParseVCloudErrorFromHttpResponseTest.java | 13 +++++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java index 9bc2f16fb3..d67e9114f3 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponse.java @@ -37,7 +37,6 @@ import org.jclouds.logging.Logger; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.util.Strings2; -import org.jclouds.vcloud.VCloudMediaType; import org.jclouds.vcloud.VCloudResponseException; import org.jclouds.vcloud.domain.VCloudError; import org.jclouds.vcloud.domain.VCloudError.MinorCode; @@ -68,19 +67,18 @@ public class ParseVCloudErrorFromHttpResponse implements HttpErrorHandler { VCloudError error = null; String message = null; if (response.getPayload() != null) { - String contentType = response.getPayload().getContentMetadata().getContentType(); - if (VCloudMediaType.ERROR_XML.equals(contentType)) { + try { error = utils.parseErrorFromContent(request, response); if (error != null) { message = error.getMessage(); exception = new VCloudResponseException(command, response, error); - } - } else { - try { + } else { message = Strings2.toStringAndClose(response.getPayload().getInput()); exception = message != null ? new HttpResponseException(command, response, message) : exception; - } catch (IOException e) { } + } catch (IOException e) { + } finally { + response.getPayload().release(); } } message = message != null ? message : String.format("%s -> %s", request.getRequestLine(), response diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java index 54b6db691b..4386e2a58a 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/util/VCloudUtils.java @@ -54,7 +54,10 @@ public class VCloudUtils { // HEAD has no content if (response.getPayload() == null) return null; - if (VCloudMediaType.ERROR_XML.equals(response.getPayload().getContentMetadata().getContentType())) { + // NOTE in vCloud Datacenter 1.5, if you make vCloud 1.0 requests, the content type + // header is suffixed with ;1.0 + String contentType = response.getPayload().getContentMetadata().getContentType(); + if (contentType != null && contentType.startsWith(VCloudMediaType.ERROR_XML)) { try { return (VCloudError) factory.create(errorHandlerProvider.get()).setContext(request).apply(response); } catch (RuntimeException e) { diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java index 996994bab2..0a79e449aa 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/handlers/ParseVCloudErrorFromHttpResponseTest.java @@ -53,6 +53,19 @@ public class ParseVCloudErrorFromHttpResponseTest extends BaseHttpErrorHandlerTe ResourceNotFoundException.class); } + @Test + public void testGet403NoAcessToEntitySetsResourceNotFoundExceptionOnAPI1_0AgainstVCD1_5() { + assertCodeMakes( + "GET", + URI.create("https://mycloud.greenhousedata.com/api/v1.0/vApp/vapp-d3a1f2cd-d07b-4ddc-bf7b-fb7468b4d95a"), + 403, + "HTTP/1.1 403", + // NOTE VCD 1.5 appends the api version to the media type + VCloudMediaType.ERROR_XML + ";1.0", + "", + ResourceNotFoundException.class); + } + @Test public void testDelete404SetsHttpResponseException() { assertCodeMakes("DELETE", URI.create("https://services.vcloudexpress.terremark.com/api/v0.8a-ext1.6/vdc/32"), From 84a34c7bf296dbf4ceec337dd410c67e2af2d0e9 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 19:11:14 -0800 Subject: [PATCH 41/82] added build version for bluelock --- providers/bluelock-vcloud-zone01/pom.xml | 2 +- .../vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/providers/bluelock-vcloud-zone01/pom.xml b/providers/bluelock-vcloud-zone01/pom.xml index ccf8d2a942..231b167aab 100644 --- a/providers/bluelock-vcloud-zone01/pom.xml +++ b/providers/bluelock-vcloud-zone01/pom.xml @@ -36,7 +36,7 @@ https://zone01.bluelock.com/api 1.0 - + 1.0.0.285979 FIXME_IDENTITY FIXME_CREDENTIAL diff --git a/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java b/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java index a29a17555e..8d0c803b0c 100644 --- a/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java +++ b/providers/bluelock-vcloud-zone01/src/main/java/org/jclouds/bluelock/vcloud/zone01/BluelockVCloudZone01PropertiesBuilder.java @@ -18,7 +18,7 @@ */ package org.jclouds.bluelock.vcloud.zone01; -import static org.jclouds.Constants.PROPERTY_ENDPOINT; +import static org.jclouds.Constants.*; import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK; @@ -37,6 +37,7 @@ public class BluelockVCloudZone01PropertiesBuilder extends VCloudPropertiesBuild Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_ISO3166_CODES, "US-IN"); properties.setProperty(PROPERTY_ENDPOINT, "https://zone01.bluelock.com/api"); + properties.setProperty(PROPERTY_BUILD_VERSION, "1.0.0.285979"); properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, "internet01-.*"); return properties; } From 3871255cccd9dca117204fb171187ee81bc6410d Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 19:11:34 -0800 Subject: [PATCH 42/82] added build version for greenhouse --- providers/greenhousedata-element-vcloud/pom.xml | 2 +- .../vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/providers/greenhousedata-element-vcloud/pom.xml b/providers/greenhousedata-element-vcloud/pom.xml index bfa5dbd11e..bf3944e966 100644 --- a/providers/greenhousedata-element-vcloud/pom.xml +++ b/providers/greenhousedata-element-vcloud/pom.xml @@ -36,7 +36,7 @@ https://mycloud.greenhousedata.com/api 1.0 - + 1.5.0.464915 FIXME_IDENTITY FIXME_CREDENTIAL diff --git a/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java b/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java index e4bcc9fd51..2e832511bd 100644 --- a/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java +++ b/providers/greenhousedata-element-vcloud/src/main/java/org/jclouds/greenhousedata/element/vcloud/GreenHouseDataElementVCloudPropertiesBuilder.java @@ -18,6 +18,7 @@ */ package org.jclouds.greenhousedata.element.vcloud; +import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK; @@ -36,6 +37,7 @@ public class GreenHouseDataElementVCloudPropertiesBuilder extends VCloudProperti Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_ISO3166_CODES, "US-WY"); properties.setProperty(PROPERTY_ENDPOINT, "https://mycloud.greenhousedata.com/api"); + properties.setProperty(PROPERTY_BUILD_VERSION, "1.5.0.464915"); properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, "orgNet-.*-External"); return properties; } From c964b207a753430428994b01d483755acfe6b0a6 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 19:23:39 -0800 Subject: [PATCH 43/82] Issue 710: public templates are now readable --- .../vcloud/compute/functions/HardwareForVAppTemplate.java | 6 +++++- .../vcloud/compute/functions/ImageForVAppTemplate.java | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java index 2da38fe37f..0984e0c9da 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java @@ -81,7 +81,11 @@ public class HardwareForVAppTemplate implements Function } VirtualHardwareSection hardware = Iterables.get(ovf.getVirtualSystem().getVirtualHardwareSections(), 0); HardwareBuilder builder = rasdToHardwareBuilder.apply(hardware.getItems()); - builder.location(findLocationForResource.apply(checkNotNull(from.getVDC(), "VDC"))); + if (from.getVDC() != null) { + builder.location(findLocationForResource.apply(from.getVDC())); + } else { + // otherwise, it could be in a public catalog, which is not assigned to a VDC + } builder.ids(from.getHref().toASCIIString()).name(from.getName()).supportsImage( ImagePredicates.idEquals(from.getHref().toASCIIString())); return builder.build(); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java index 7cd0606f59..99d1780e52 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java @@ -53,7 +53,11 @@ public class ImageForVAppTemplate implements Function { builder.ids(from.getHref().toASCIIString()); builder.uri(from.getHref()); builder.name(from.getName()); - builder.location(findLocationForResource.apply(checkNotNull(from.getVDC(), "VDC"))); + if (from.getVDC() != null) { + builder.location(findLocationForResource.apply(from.getVDC())); + } else { + // otherwise, it could be in a public catalog, which is not assigned to a VDC + } builder.description(from.getDescription() != null ? from.getDescription() : from.getName()); Envelope ovf = client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(from.getHref()); builder.operatingSystem(CIMOperatingSystem.toComputeOs(ovf)); From ea81b058a428a606fe58f4c9194d32c00462fc43 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 12 Jan 2012 19:24:30 -0800 Subject: [PATCH 44/82] Issue 710: added expect test for vCloud --- .../BaseVCloudComputeServiceExpectTest.java | 161 ++++ .../ListImagesInVCloudExpectTest.java | 88 ++ .../src/test/resources/catalog1.0-vcd15.xml | 9 + .../test/resources/catalogItem1.0-vcd15.xml | 8 + .../src/test/resources/org1.0-vcd15.xml | 11 + .../src/test/resources/orgList1.0-vcd15.xml | 4 + .../src/test/resources/ovf-ubuntu64.xml | 148 +++ .../src/test/resources/template1.0-vcd15.xml | 72 ++ .../src/test/resources/vdc1.0-vcd15.xml | 47 + .../src/test/resources/versions-vcd15.xml | 906 ++++++++++++++++++ 10 files changed, 1454 insertions(+) create mode 100644 apis/vcloud/src/test/java/org/jclouds/vcloud/compute/BaseVCloudComputeServiceExpectTest.java create mode 100644 apis/vcloud/src/test/java/org/jclouds/vcloud/compute/functions/ListImagesInVCloudExpectTest.java create mode 100644 apis/vcloud/src/test/resources/catalog1.0-vcd15.xml create mode 100644 apis/vcloud/src/test/resources/catalogItem1.0-vcd15.xml create mode 100644 apis/vcloud/src/test/resources/org1.0-vcd15.xml create mode 100644 apis/vcloud/src/test/resources/orgList1.0-vcd15.xml create mode 100644 apis/vcloud/src/test/resources/ovf-ubuntu64.xml create mode 100644 apis/vcloud/src/test/resources/template1.0-vcd15.xml create mode 100644 apis/vcloud/src/test/resources/vdc1.0-vcd15.xml create mode 100644 apis/vcloud/src/test/resources/versions-vcd15.xml diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/BaseVCloudComputeServiceExpectTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/BaseVCloudComputeServiceExpectTest.java new file mode 100644 index 0000000000..833e9ba46e --- /dev/null +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/BaseVCloudComputeServiceExpectTest.java @@ -0,0 +1,161 @@ +/** + * 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.vcloud.compute; + +import java.net.URI; +import java.util.Properties; + +import javax.ws.rs.core.MediaType; + +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceContextFactory; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.logging.config.NullLoggingModule; +import org.jclouds.rest.BaseRestClientExpectTest; +import org.jclouds.vcloud.VCloudMediaType; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.net.HttpHeaders; +import com.google.inject.Module; + +/** + * Base class for writing VCloud Expect tests for ComputeService operations + * + * @author Adrian Cole + */ +public abstract class BaseVCloudComputeServiceExpectTest extends BaseRestClientExpectTest { + protected static final String ENDPOINT = "https://zone.myvcloud.com/api"; + + protected HttpRequest versionsRequest = HttpRequest.builder().method("GET").endpoint( + URI.create(ENDPOINT + "/versions")).build(); + + protected HttpResponse versionsResponseFromVCD1_5 = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/versions-vcd15.xml", "text/xml")) + .build(); + + // initial auth is using basic + protected HttpRequest version1_0LoginRequest = HttpRequest.builder().method("POST").endpoint( + URI.create(ENDPOINT + "/v1.0/login")) + .headers(ImmutableMultimap. builder() + .put(HttpHeaders.ACCEPT, VCloudMediaType.ORGLIST_XML) + .put(HttpHeaders.AUTHORIZATION, "Basic dXNlckBvcmc6cGFzc3dvcmQ=").build()).build(); + + protected String sessionToken = "AtatAgvJMrwOc9pDQq4RRCRLazThpnTKJDxSVH9oB2I="; + + // login response includes a cookie and also a vcloud extended header with the session token in it + // NOTE: vCloud Director 1.5 returns ;version=1.0 on responses to requests made in 1.0 format. + protected HttpResponse successfulVersion1_0LoginResponseFromVCD1_5WithSingleOrg = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/orgList1.0-vcd15.xml", VCloudMediaType.ORGLIST_XML +";version=1.0")) + .headers(ImmutableMultimap. builder() + .put("x-vcloud-authorization", sessionToken) + .put(HttpHeaders.SET_COOKIE, String.format("vcloud-token=%s; Secure; Path=/", sessionToken)).build()).build(); + + // objects are looked up by id and the format of the id is hex-hyphen + protected String orgId = "c076f90a-397a-49fa-89b8-b294c1599cd0"; + + protected HttpRequest version1_0GetOrgRequest = HttpRequest.builder().method("GET").endpoint( + URI.create(ENDPOINT + "/v1.0/org/" + orgId)) + .headers(ImmutableMultimap. builder() + .put(HttpHeaders.ACCEPT, VCloudMediaType.ORG_XML) + .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build(); + + protected HttpResponse successfulVersion1_0GetOrgResponseFromVCD1_5WithSingleTasksListVDCAndNetwork = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/org1.0-vcd15.xml", VCloudMediaType.ORG_XML +";version=1.0")) + .build(); + + protected String catalogId = "3155f393-1e1d-4572-8c9c-d76f72ddb658"; + protected String vdcId = "e9cd3387-ac57-4d27-a481-9bee75e0690f"; + + protected HttpRequest version1_0GetCatalogRequest = HttpRequest.builder().method("GET").endpoint( + URI.create(ENDPOINT + "/v1.0/catalog/" + catalogId)) + .headers(ImmutableMultimap. builder() + .put(HttpHeaders.ACCEPT, VCloudMediaType.CATALOG_XML) + .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build(); + + protected HttpResponse successfulVersion1_0GetCatalogResponseFromVCD1_5WithSingleTemplate = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/catalog1.0-vcd15.xml", VCloudMediaType.CATALOG_XML +";version=1.0")) + .build(); + + protected String catalogItemId = "ceb369f7-1d07-4e32-9dbd-ebb5aa6ca55c"; + + protected HttpRequest version1_0GetCatalogItemRequest = HttpRequest.builder().method("GET").endpoint( + URI.create(ENDPOINT + "/v1.0/catalogItem/" + catalogItemId)) + .headers(ImmutableMultimap. builder() + .put(HttpHeaders.ACCEPT, VCloudMediaType.CATALOGITEM_XML) + .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build(); + + protected HttpResponse successfulVersion1_0GetCatalogItemResponseFromVCD1_5ForTemplate = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/catalogItem1.0-vcd15.xml", VCloudMediaType.CATALOGITEM_XML +";version=1.0")) + .build(); + + // note vAppTemplate has a prefix in its id + protected String templateId = "vappTemplate-51891b97-c5dd-47dc-a687-aabae354f728"; + + protected HttpRequest version1_0GetVDCRequest = HttpRequest.builder().method("GET").endpoint( + URI.create(ENDPOINT + "/v1.0/vdc/" + vdcId)) + .headers(ImmutableMultimap. builder() + .put(HttpHeaders.ACCEPT, VCloudMediaType.VDC_XML) + .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build(); + + protected HttpResponse successfulVersion1_0GetVDCResponseFromVCD1_5WithSingleTemplateAndNetwork = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/vdc1.0-vcd15.xml", VCloudMediaType.VDC_XML +";version=1.0")) + .build(); + + protected String networkId = "b466c0c5-8a5c-4335-b703-a2e2e6b5f3e1"; + + protected HttpRequest version1_0GetVAppTemplateRequest = HttpRequest.builder().method("GET").endpoint( + URI.create(ENDPOINT + "/v1.0/vAppTemplate/" + templateId)) + .headers(ImmutableMultimap. builder() + .put(HttpHeaders.ACCEPT, VCloudMediaType.VAPPTEMPLATE_XML) + .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build(); + + protected HttpResponse successfulVersion1_0GetVAppTemplateResponseFromVCD1_5WithSingleVMAndVDCParent = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/template1.0-vcd15.xml", VCloudMediaType.VAPPTEMPLATE_XML +";version=1.0")) + .build(); + + protected HttpRequest version1_0GetOVFForVAppTemplateRequest = HttpRequest.builder().method("GET").endpoint( + URI.create(ENDPOINT + "/v1.0/vAppTemplate/" + templateId + "/ovf")) + .headers(ImmutableMultimap. builder() + .put(HttpHeaders.ACCEPT, MediaType.TEXT_XML) + .put(HttpHeaders.COOKIE, "vcloud-token=" + sessionToken).build()).build(); + + protected HttpResponse successfulVersion1_0GetOVFForVAppTemplateResponseFromVCD1_5WithSingleVM = HttpResponse.builder().statusCode(200) + .message("HTTP/1.1 200 OK").payload(payloadFromResourceWithContentType("/ovf-ubuntu64.xml", MediaType.TEXT_XML +";version=1.0")) + .build(); + + public BaseVCloudComputeServiceExpectTest() { + provider = "vcloud"; + } + + @Override + public ComputeService createClient(Function fn, Module module, Properties props) { + return new ComputeServiceContextFactory(setupRestProperties()) + .createContext(provider, "user@org", "password", ImmutableSet. of(new ExpectModule(fn), + new NullLoggingModule(), module), props).getComputeService(); + } + @Override + protected Properties setupProperties() { + Properties props = super.setupProperties(); + props.setProperty(provider+".endpoint", ENDPOINT); + return props; + } +} diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/functions/ListImagesInVCloudExpectTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/functions/ListImagesInVCloudExpectTest.java new file mode 100644 index 0000000000..083ba3f1f8 --- /dev/null +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/functions/ListImagesInVCloudExpectTest.java @@ -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.vcloud.compute.functions; + +import static org.testng.Assert.assertEquals; + +import java.net.URI; +import java.util.Set; + +import org.jclouds.cim.OSType; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.domain.CIMOperatingSystem; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.location.suppliers.JustProvider; +import org.jclouds.vcloud.compute.BaseVCloudComputeServiceExpectTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +/** + * + * @author Adrian Cole + */ +@Test(singleThreaded = true, testName = "ListImagesInVCloudExpectTest") +public class ListImagesInVCloudExpectTest extends BaseVCloudComputeServiceExpectTest { + + public void testListImagesUsingVCloud1_0ApiOnServerRunningVCloudDirector1_5ReturnsImageWithLocationForVAppTemplateInVDC() throws Exception { + ComputeService compute = requestsSendResponses(ImmutableMap.builder() + .put(versionsRequest, versionsResponseFromVCD1_5) + .put(version1_0LoginRequest, successfulVersion1_0LoginResponseFromVCD1_5WithSingleOrg) + .put(version1_0GetOrgRequest, successfulVersion1_0GetOrgResponseFromVCD1_5WithSingleTasksListVDCAndNetwork) + .put(version1_0GetCatalogRequest, successfulVersion1_0GetCatalogResponseFromVCD1_5WithSingleTemplate) + .put(version1_0GetCatalogItemRequest, successfulVersion1_0GetCatalogItemResponseFromVCD1_5ForTemplate) + .put(version1_0GetVDCRequest, successfulVersion1_0GetVDCResponseFromVCD1_5WithSingleTemplateAndNetwork) + .put(version1_0GetVAppTemplateRequest, successfulVersion1_0GetVAppTemplateResponseFromVCD1_5WithSingleVMAndVDCParent) + .put(version1_0GetOVFForVAppTemplateRequest, successfulVersion1_0GetOVFForVAppTemplateResponseFromVCD1_5WithSingleVM) + .build()); + + Location provider = Iterables.getOnlyElement(compute.getContext().utils().injector().getInstance(JustProvider.class).get()); + + Location orgLocation = new LocationBuilder().id(ENDPOINT + "/v1.0/org/" + orgId).scope(LocationScope.REGION) + .description("jclouds").parent(provider).build(); + + Location vdcLocation = new LocationBuilder().id(ENDPOINT + "/v1.0/vdc/" + vdcId).scope(LocationScope.ZONE) + .description("orgVDC-jclouds-Tier1-PAYG").parent(orgLocation).build(); + + Set currentImages = compute.listImages(); + assertEquals(compute.listImages().size(), 1); + Image onlyImage = Iterables.get(currentImages, 0); + + + Image expectedImage = new ImageBuilder() + .ids(ENDPOINT + "/v1.0/vAppTemplate/" + templateId) + .uri(URI.create(ENDPOINT + "/v1.0/vAppTemplate/" + templateId)) + .name("UbuntuServer-x64-2GB") + .operatingSystem(new CIMOperatingSystem(OSType.UBUNTU_64, "", null, "Ubuntu Linux (64-bit)")) + // TODO: this looks like a bug, as it says network interfaces + .description("This is a special place-holder used for disconnected network interfaces.") + .defaultCredentials(LoginCredentials.builder().identity("root").build()) + .location(vdcLocation).build(); + + assertEquals(onlyImage, expectedImage); + } +} diff --git a/apis/vcloud/src/test/resources/catalog1.0-vcd15.xml b/apis/vcloud/src/test/resources/catalog1.0-vcd15.xml new file mode 100644 index 0000000000..0208e5947a --- /dev/null +++ b/apis/vcloud/src/test/resources/catalog1.0-vcd15.xml @@ -0,0 +1,9 @@ + + + + + + + + false + \ No newline at end of file diff --git a/apis/vcloud/src/test/resources/catalogItem1.0-vcd15.xml b/apis/vcloud/src/test/resources/catalogItem1.0-vcd15.xml new file mode 100644 index 0000000000..b344071608 --- /dev/null +++ b/apis/vcloud/src/test/resources/catalogItem1.0-vcd15.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/apis/vcloud/src/test/resources/org1.0-vcd15.xml b/apis/vcloud/src/test/resources/org1.0-vcd15.xml new file mode 100644 index 0000000000..d0ca5b725c --- /dev/null +++ b/apis/vcloud/src/test/resources/org1.0-vcd15.xml @@ -0,0 +1,11 @@ + + + + + + + + + Customer jclouds + jclouds + \ No newline at end of file diff --git a/apis/vcloud/src/test/resources/orgList1.0-vcd15.xml b/apis/vcloud/src/test/resources/orgList1.0-vcd15.xml new file mode 100644 index 0000000000..40f3cbe788 --- /dev/null +++ b/apis/vcloud/src/test/resources/orgList1.0-vcd15.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/apis/vcloud/src/test/resources/ovf-ubuntu64.xml b/apis/vcloud/src/test/resources/ovf-ubuntu64.xml new file mode 100644 index 0000000000..767957362b --- /dev/null +++ b/apis/vcloud/src/test/resources/ovf-ubuntu64.xml @@ -0,0 +1,148 @@ + + + + + The list of logical networks + + This is a special place-holder used for disconnected network interfaces. + + + + The configuration parameters for logical networks + + This is a special place-holder used for disconnected network interfaces. + + + false + 196.254.254.254 + 255.255.0.0 + 196.254.254.254 + + isolated + + false + + + + Lease settings section + 0 + 5184000 + 2012-03-12T17:40:44.491-06:00 + + + VApp template customization section + true + + + A virtual machine: + UbuntuServer-x64-2GB + + Specifies the operating system installed + Ubuntu Linux (64-bit) + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + UbuntuServer-x64-2GB + vmx-07 + + + 00:50:56:01:02:9f + 0 + false + none + PCNet32 ethernet adapter + Network adapter 0 + 1 + PCNet32 + 10 + + + 0 + SCSI Controller + SCSI Controller 0 + 2 + lsilogic + 6 + + + 0 + Hard disk + Hard disk 1 + + 2000 + 2 + 17 + + + 0 + IDE Controller + IDE Controller 0 + 3 + 5 + + + 0 + false + CD/DVD Drive + CD/DVD Drive 1 + + 3000 + 3 + 15 + + + 0 + false + Floppy Drive + Floppy Drive 1 + + 8000 + 14 + + + hertz * 10^6 + Number of Virtual CPUs + 1 virtual CPU(s) + 4 + 0 + 3 + 1 + 0 + + + byte * 2^20 + Memory Size + 256 MB of memory + 5 + 0 + 4 + 256 + 0 + + + + Specifies the available VM network connections + 0 + + 0 + false + 00:50:56:01:02:9f + NONE + + + + Specifies Guest OS Customization Settings + true + false + false + false + true + true + false + UbuntuServer + + + \ No newline at end of file diff --git a/apis/vcloud/src/test/resources/template1.0-vcd15.xml b/apis/vcloud/src/test/resources/template1.0-vcd15.xml new file mode 100644 index 0000000000..35393eec2f --- /dev/null +++ b/apis/vcloud/src/test/resources/template1.0-vcd15.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + Specifies the available VM network connections + 0 + + 0 + false + 00:50:56:01:02:9f + NONE + + + + Specifies Guest OS Customization Settings + true + false + false + false + true + true + false + UbuntuServer + + f114ade7-a63f-4f8b-b30b-44e9ff77e068 + + + + The list of logical networks + + This is a special place-holder used for disconnected network interfaces. + + + + The configuration parameters for logical networks + + This is a special place-holder used for disconnected network interfaces. + + + false + 196.254.254.254 + 255.255.0.0 + 196.254.254.254 + + isolated + + false + + + + Lease settings section + + 5184000 + 2012-03-12T17:40:44.491-06:00 + + + VApp template customization section + true + + \ No newline at end of file diff --git a/apis/vcloud/src/test/resources/vdc1.0-vcd15.xml b/apis/vcloud/src/test/resources/vdc1.0-vcd15.xml new file mode 100644 index 0000000000..d705891a0c --- /dev/null +++ b/apis/vcloud/src/test/resources/vdc1.0-vcd15.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + Pay As You go resources for organization jclouds + AllocationVApp + + MB + 0 + 0 + 14336 + 0 + + + + MHz + 0 + 0 + 0 + 0 + + + MB + 0 + 0 + 0 + 0 + + + + + + + + + 0 + 10 + 10 + true + \ No newline at end of file diff --git a/apis/vcloud/src/test/resources/versions-vcd15.xml b/apis/vcloud/src/test/resources/versions-vcd15.xml new file mode 100644 index 0000000000..ed24d3a8b4 --- /dev/null +++ b/apis/vcloud/src/test/resources/versions-vcd15.xml @@ -0,0 +1,906 @@ + + + + 1.0 + https://zone.myvcloud.com/api/v1.0/login + + application/vnd.vmware.vcloud.customizationSection+xml + CustomizationSectionType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.catalogItem+xml + CatalogItemType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.networkConnectionSection+xml + NetworkConnectionSectionType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.owner+xml + OwnerType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.licensingReportList+xml + LicensingReportListType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.group+xml + GroupType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vdc+xml + AdminVdcType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.licensingReport+xml + LicensingReportType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.importVmAsVAppTemplateParams+xml + ImportVmAsVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwVimServerReferences+xml + VMWVimServerReferencesType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.vm+xml + VmType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml + UploadVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.composeVAppParams+xml + ComposeVAppParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.orgList+xml + OrgListType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.cloneMediaParams+xml + CloneMediaParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.vmPendingQuestion+xml + VmPendingQuestionType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vmwHostReferences+xml + VMWHostReferencesType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.undeployVAppParams+xml + UndeployVAppParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.leaseSettingsSection+xml + LeaseSettingsSectionType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.network+xml + OrgNetworkType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.deployVAppParams+xml + DeployVAppParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.cloneVAppTemplateParams+xml + CloneVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.media+xml + MediaType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vmwprovidervdc+xml + VMWProviderVdcType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.vAppTemplate+xml + VAppTemplateType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.org+xml + OrgType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.vApp+xml + VAppType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.catalog+xml + CatalogType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vmwNetworkPool+xml + VMWNetworkPoolType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.tasksList+xml + TasksListType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vdcReferences+xml + VdcReferencesType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.screenTicket+xml + ScreenTicketType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.prepareHostParams+xml + PrepareHostParamsType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vcloud+xml + VCloudType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.publishCatalogParams+xml + PublishCatalogParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.networkConfigSection+xml + NetworkConfigSectionType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.resourcePoolList+xml + ResourcePoolListType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.right+xml + RightType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vmwExtension+xml + VMWExtensionType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.importVmAsVAppParams+xml + ImportVmAsVAppParamsType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwvirtualcenter+xml + VimServerType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmsObjectRefsList+xml + VmObjectRefsListType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.controlAccess+xml + ControlAccessParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.vdc+xml + VdcType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.role+xml + RoleType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.cloneVAppParams+xml + CloneVAppParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.host+xml + HostType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.organization+xml + AdminOrgType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.providervdc+xml + ProviderVdcType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.user+xml + UserType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vmwProviderVdcReferences+xml + VMWProviderVdcReferencesType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml + MediaInsertOrEjectParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml + InstantiateVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.rasdItemsList+xml + RasdItemsListType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.task+xml + TaskType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.vmwNetworkPoolReferences+xml + VMWNetworkPoolReferencesType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.guestCustomizationSection+xml + GuestCustomizationSectionType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.recomposeVAppParams+xml + RecomposeVAppParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.importMediaParams+xml + ImportMediaParamsType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwExternalNetworkReferences+xml + VMWExternalNetworkReferencesType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwexternalnet+xml + VMWExternalNetworkType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.captureVAppParams+xml + CaptureVAppParamsType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.vmPendingAnswer+xml + VmQuestionAnswerType + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.admin.registerVimServerParams+xml + RegisterVimServerParamsType + https://zone.myvcloud.com/api/v1.0/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.rasdItem+xml + RASD_Type + https://zone.myvcloud.com/api/v1.0/schema/master.xsd + + + application/vnd.vmware.vcloud.startupSection+xml + StartupSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + application/vnd.vmware.vcloud.virtualHardwareSection+xml + VirtualHardwareSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + application/vnd.vmware.vcloud.operatingSystemSection+xml + OperatingSystemSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + application/vnd.vmware.vcloud.networkSection+xml + NetworkSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + + 1.5 + https://zone.myvcloud.com/api/sessions + + application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml + InstantiateVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vmwProviderVdcReferences+xml + VMWProviderVdcReferencesType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.customizationSection+xml + CustomizationSectionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.prepareHostParams+xml + PrepareHostParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.relocateVmParams+xml + RelocateParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.org+xml + OrgType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vmwExternalNetworkReferences+xml + VMWExternalNetworkReferencesType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.networkConnectionSection+xml + NetworkConnectionSectionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.host+xml + HostType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.catalogItem+xml + CatalogItemType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.owner+xml + OwnerType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.vdc+xml + VdcType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vdc+xml + AdminVdcType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.catalog+xml + AdminCatalogType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.recomposeVAppParams+xml + RecomposeVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.importVmIntoExistingVAppParams+xml + ImportVmIntoExistingVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.taskExtensionRequestUpdateProgressOperationParams+xml + TaskExtensionRequestUpdateProgressParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.catalog+xml + CatalogType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.cloneVAppTemplateParams+xml + CloneVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.providervdc+xml + ProviderVdcType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vmsObjectRefsList+xml + VmObjectRefsListType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.undeployVAppParams+xml + UndeployVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vdcReferences+xml + VdcReferencesType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.systemPasswordPolicySettings+xml + SystemPasswordPolicySettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.vApp+xml + VAppType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.taskExtensionRequest+xml + TaskExtensionRequestType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vimServerNetworks+xml + VimObjectRefListType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwprovidervdc+xml + VMWProviderVdcType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.orgSettings+xml + OrgSettingsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.captureVAppParams+xml + CaptureVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.screenTicket+xml + ScreenTicketType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.runtimeInfoSection+xml + RuntimeInfoSectionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.tasksList+xml + TasksListType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.amqpSettingsTest+xml + AmqpSettingsTestType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.extensionSettings+xml + TaskExtensionSettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.importVmAsVAppTemplateParams+xml + ImportVmAsVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.organizationGeneralSettings+xml + OrgGeneralSettingsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.registerVimServerParams+xml + RegisterVimServerParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.network+xml + OrgNetworkType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml + UploadVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.datastore+xml + DatastoreType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.metadata+xml + MetadataType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.licensingReportList+xml + LicensingReportListType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwNetworkPool+xml + VMWNetworkPoolType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.systemSettings+xml + SystemSettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwHostReferences+xml + VMWHostReferencesType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.taskExtensionRequestOperationParams+xml + TaskExtensionRequestOperationParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.metadata.value+xml + MetadataValueType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.taskOperationList+xml + TaskOperationListType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.media+xml + MediaType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.productSections+xml + ProductSectionListType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.amqpSettings+xml + AmqpSettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.vAppTemplate+xml + VAppTemplateType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.deployVAppParams+xml + DeployVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.importVmIntoExistingVAppTemplateParams+xml + ImportVmIntoExistingVAppTemplateParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.resourcePoolList+xml + ResourcePoolListType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.networkConfigSection+xml + NetworkConfigSectionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.OrganizationVdcResourcePoolSet+xml + OrganizationResourcePoolSetType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.organizationPasswordPolicySettings+xml + OrgPasswordPolicySettingsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.publishCatalogParams+xml + PublishCatalogParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vmwExtension+xml + VMWExtensionType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml + MediaInsertOrEjectParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.vmPendingQuestion+xml + VmPendingQuestionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.notificationsSettings+xml + NotificationsSettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.ldapUserSettings+xml + LdapUserAttributesType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.right+xml + RightType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.ldapSettings+xml + LdapSettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.organization+xml + AdminOrgType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.orgList+xml + OrgListType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vAppTemplateLeaseSettings+xml + OrgVAppTemplateLeaseSettingsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vmwVimServerReferences+xml + VMWVimServerReferencesType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwexternalnet+xml + VMWExternalNetworkType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.entity+xml + EntityType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.cloneMediaParams+xml + CloneMediaParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.licensingReport+xml + LicensingReportType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.importMediaParams+xml + ImportMediaParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.resourcePoolSetUpdateParams+xml + UpdateResourcePoolSetParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.taskExtensionRequestList+xml + ReferencesType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.vmPendingAnswer+xml + VmQuestionAnswerType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.rasdItemsList+xml + RasdItemsListType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.generalSettings+xml + GeneralSettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwNetworkPoolReferences+xml + VMWNetworkPoolReferencesType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.group+xml + GroupType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.controlAccess+xml + ControlAccessParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.ldapGroupSettings+xml + LdapGroupAttributesType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.user+xml + UserType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vcloud+xml + VCloudType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.uberAdminSettings+xml + UberAdminSettingsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.vmwvirtualcenter+xml + VimServerType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.leaseSettingsSection+xml + LeaseSettingsSectionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.composeVAppParams+xml + ComposeVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.organizationEmailSettings+xml + OrgEmailSettingsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.vm+xml + VmType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vmwProviderVdcResourcePoolSet+xml + VMWProviderVdcResourcePoolSetType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.vcloud.cloneVAppParams+xml + CloneVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.guestCustomizationSection+xml + GuestCustomizationSectionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.task+xml + TaskType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.session+xml + SessionType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vAppLeaseSettings+xml + OrgLeaseSettingsType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.importVmAsVAppParams+xml + ImportVmAsVAppParamsType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + application/vnd.vmware.admin.role+xml + RoleType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.rasdItem+xml + RASD_Type + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.startupSection+xml + StartupSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + application/vnd.vmware.vcloud.virtualHardwareSection+xml + VirtualHardwareSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + application/vnd.vmware.vcloud.operatingSystemSection+xml + OperatingSystemSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + application/vnd.vmware.vcloud.networkSection+xml + NetworkSection_Type + http://schemas.dmtf.org/ovf/envelope/1/dsp8023_1.1.0.xsd + + + application/vnd.vmware.vcloud.vAppNetwork+xml + VAppNetworkType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.network+xml + NetworkType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.vcloud.orgNetwork+xml + OrgNetworkType + https://zone.myvcloud.com/api/v1.5/schema/master.xsd + + + application/vnd.vmware.admin.vmwexternalnet+xml + VMWExternalNetworkType + https://zone.myvcloud.com/api/v1.5/schema/vmwextensions.xsd + + + From 6c47f43a98e92350f3c50f2b6a08cefcf817dbfd Mon Sep 17 00:00:00 2001 From: Christophe Hamerling Date: Fri, 13 Jan 2012 12:30:57 +0100 Subject: [PATCH 45/82] Fix comments and add keyName field in Server class --- .../openstack/nova/NovaAsyncClient.java | 2 +- .../jclouds/openstack/nova/NovaClient.java | 12 ++++++++--- .../openstack/nova/domain/FloatingIP.java | 5 +++-- .../jclouds/openstack/nova/domain/Server.java | 20 ++++++++++++++++++- .../nova/options/CreateServerOptions.java | 11 ++++++++-- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java index 874706a744..505f76d0db 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaAsyncClient.java @@ -323,7 +323,7 @@ public interface NovaAsyncClient { @Consumes @Produces(MediaType.APPLICATION_JSON) @Payload("%7B\"addFloatingIp\":%7B\"address\":\"{address}\"%7D%7D") - ListenableFuture addFloatingIp(@PathParam("id") int serverId, @PayloadParam("address") String ip); + ListenableFuture addFloatingIP(@PathParam("id") int serverId, @PayloadParam("address") String ip); @GET @Unwrap diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java index 768959690e..45a32e7545 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/NovaClient.java @@ -288,21 +288,27 @@ public interface NovaClient { * directly add the floating IP just after creating the server but have to * poll if the server has an IP. * + * @see http://wiki.openstack.org/os_api_floating_ip + * @since 2011.3 "Diablo" release, OpenStack API 1.1 * @param serverId * @param ip */ - void addFloatingIp(int serverId, String ip); + void addFloatingIP(int serverId, String ip); /** - * Get all the defined floating IPs + * Get all the defined floating IPs in nova * - * @return + * @see http://wiki.openstack.org/os_api_floating_ip + * @since 2011.3 "Diablo" release, OpenStack API 1.1 + * @return all the available floating IP for the current tenant */ Set listFloatingIPs(); /** * Get floating IP details from its ID * + * @see http://wiki.openstack.org/os_api_floating_ip + * @since 2011.3 "Diablo" release, OpenStack API 1.1 * @param id the floating IP id * @return the floating IP or null if not found */ diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java index 591f2034f7..cefc53b84d 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/FloatingIP.java @@ -21,10 +21,11 @@ package org.jclouds.openstack.nova.domain; import com.google.gson.annotations.SerializedName; /** - * Check Floating IP Wiki page + * Check Floating IP Wiki + * page. Available since OpenStack Diablo release and API 1.1. * * @author chamerling - * + * */ public class FloatingIP extends Resource { diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java index a375165b2b..cc340849b4 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Server.java @@ -19,6 +19,7 @@ package org.jclouds.openstack.nova.domain; import com.google.common.collect.Maps; +import com.google.gson.annotations.SerializedName; import java.util.Date; import java.util.Map; @@ -45,6 +46,9 @@ public class Server extends Resource { private Flavor flavor; private Image image; + @SerializedName(value="key_name") + private String keyName; + private Date created; private Date updated; @@ -191,6 +195,14 @@ public class Server extends Resource { public void setImage(Image image) { this.image = image; } + + public String getKeyName() { + return keyName; + } + + public void setKeyName(String keyName) { + this.keyName = keyName; + } @Override public int hashCode() { @@ -204,6 +216,7 @@ public class Server extends Resource { result = prime * result + ((imageRef == null) ? 0 : imageRef.hashCode()); result = prime * result + ((metadata == null) ? 0 : metadata.hashCode()); result = prime * result + ((uuid == null) ? 0 : uuid.hashCode()); + result = prime * result + ((keyName == null) ? 0 : keyName.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((flavor == null) ? 0 : flavor.hashCode()); result = prime * result + ((image == null) ? 0 : image.hashCode()); @@ -256,6 +269,11 @@ public class Server extends Resource { return false; } else if (!uuid.equals(other.uuid)) return false; + if (keyName == null) { + if (other.keyName != null) + return false; + } else if (!keyName.equals(other.keyName)) + return false; if (name == null) { if (other.name != null) return false; @@ -282,7 +300,7 @@ public class Server extends Resource { public String toString() { return "Server [addresses=" + addresses + ", adminPass=" + adminPass + ", flavorRef=" + flavorRef + ", hostId=" + hostId + ", id=" + id + ", imageRef=" + imageRef - + ", metadata=" + metadata + ", uuid=" + uuid + ", name=" + name + "]"; + + ", metadata=" + metadata + ", uuid=" + uuid + ", name=" + name + ", keyName=" + keyName + "]"; } } diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java index 1d024bf7a0..185ee33b61 100644 --- a/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java +++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/options/CreateServerOptions.java @@ -147,7 +147,14 @@ public class CreateServerOptions implements MapBinder { 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; @@ -173,7 +180,7 @@ public class CreateServerOptions implements MapBinder { } /** - * @see CreateServerOptions#withKeyPair(String) + * @see CreateServerOptions#withKeyName(String) */ public static CreateServerOptions withKeyName(String keyName) { CreateServerOptions options = new CreateServerOptions(); From e608674f934c1c2c0cf0c54b245428240194a3e8 Mon Sep 17 00:00:00 2001 From: andreisavu Date: Fri, 13 Jan 2012 16:11:27 +0200 Subject: [PATCH 46/82] Implemented Domain API for Domain Admin --- .../CloudStackDomainAsyncClient.java | 7 + .../cloudstack/CloudStackDomainClient.java | 7 + .../config/CloudStackRestClientModule.java | 3 + .../org/jclouds/cloudstack/domain/Domain.java | 192 ++++++++++++++++++ .../features/DomainDomainAsyncClient.java | 83 ++++++++ .../features/DomainDomainClient.java | 70 +++++++ .../options/ListDomainChildrenOptions.java | 133 ++++++++++++ .../options/ListDomainsOptions.java | 132 ++++++++++++ .../DomainDomainClientExpectTest.java | 182 +++++++++++++++++ .../features/DomainDomainClientLiveTest.java | 95 +++++++++ .../parse/ListDomainsResponseTest.java | 65 ++++++ .../src/test/resources/getdomainresponse.json | 2 + .../resources/listdomainchildrenresponse.json | 3 + .../test/resources/listdomainsresponse.json | 3 + 14 files changed, 977 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Domain.java create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainAsyncClient.java create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainClient.java create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainChildrenOptions.java create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainsOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientExpectTest.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientLiveTest.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListDomainsResponseTest.java create mode 100644 apis/cloudstack/src/test/resources/getdomainresponse.json create mode 100644 apis/cloudstack/src/test/resources/listdomainchildrenresponse.json create mode 100644 apis/cloudstack/src/test/resources/listdomainsresponse.json diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java index fc89a311d7..941ee5515e 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainAsyncClient.java @@ -19,6 +19,7 @@ package org.jclouds.cloudstack; import org.jclouds.cloudstack.features.DomainAccountAsyncClient; +import org.jclouds.cloudstack.features.DomainDomainAsyncClient; import org.jclouds.cloudstack.features.DomainLimitAsyncClient; import org.jclouds.cloudstack.features.DomainUserAsyncClient; import org.jclouds.rest.annotations.Delegate; @@ -55,4 +56,10 @@ public interface CloudStackDomainAsyncClient extends CloudStackAsyncClient { @Delegate DomainUserAsyncClient getUserClient(); + /** + * Provides asynchronous access to Domains + */ + @Delegate + DomainDomainAsyncClient getDomainClient(); + } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java index 62a29ea2e2..10537a505c 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackDomainClient.java @@ -21,6 +21,7 @@ package org.jclouds.cloudstack; import java.util.concurrent.TimeUnit; import org.jclouds.cloudstack.features.DomainAccountClient; +import org.jclouds.cloudstack.features.DomainDomainClient; import org.jclouds.cloudstack.features.DomainLimitClient; import org.jclouds.cloudstack.features.DomainUserClient; import org.jclouds.concurrent.Timeout; @@ -58,4 +59,10 @@ public interface CloudStackDomainClient extends CloudStackClient { */ @Delegate DomainUserClient getUserClient(); + + /** + * Provides synchronous access to Domains + */ + @Delegate + DomainDomainClient getDomainClient(); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java index 2c28734536..f4b060f2df 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java @@ -40,6 +40,8 @@ import org.jclouds.cloudstack.features.ConfigurationAsyncClient; import org.jclouds.cloudstack.features.ConfigurationClient; import org.jclouds.cloudstack.features.DomainAccountAsyncClient; import org.jclouds.cloudstack.features.DomainAccountClient; +import org.jclouds.cloudstack.features.DomainDomainAsyncClient; +import org.jclouds.cloudstack.features.DomainDomainClient; import org.jclouds.cloudstack.features.DomainLimitAsyncClient; import org.jclouds.cloudstack.features.DomainLimitClient; import org.jclouds.cloudstack.features.DomainUserAsyncClient; @@ -144,6 +146,7 @@ public class CloudStackRestClientModule extends RestClientModule { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private long id; + private boolean hasChild; + private long level; + private String name; + private String networkDomain; + private long parentDomainId; + private String parentDomainName; + + public Builder id(long id) { + this.id = id; + return this; + } + + public Builder hasChild(boolean hasChild) { + this.hasChild = hasChild; + return this; + } + + public Builder level(long level) { + this.level = level; + return this; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder networkDomain(String networkDomain) { + this.networkDomain = networkDomain; + return this; + } + + public Builder parentDomainId(long parentDomainId) { + this.parentDomainId = parentDomainId; + return this; + } + + public Builder parentDomainName(String parentDomainName) { + this.parentDomainName = parentDomainName; + return this; + } + + public Domain build() { + return new Domain(id, hasChild, level, name, networkDomain, + parentDomainId, parentDomainName); + } + } + + // for deserialization + Domain() { + } + + private long id; + @SerializedName("haschild") + private boolean hasChild; + private long level; + private String name; + @SerializedName("networkdomain") + private String networkDomain; + @SerializedName("parentdomainid") + private long parentDomainId; + @SerializedName("parentdomainname") + private String parentDomainName; + + public Domain(long id, boolean hasChild, long level, String name, String networkDomain, + long parentDomainId, String parentDomainName) { + this.id = id; + this.hasChild = hasChild; + this.level = level; + this.name = name; + this.networkDomain = networkDomain; + this.parentDomainId = parentDomainId; + this.parentDomainName = parentDomainName; + } + + public long getId() { + return id; + } + + public boolean hasChild() { + return hasChild; + } + + public long getLevel() { + return level; + } + + public String getName() { + return name; + } + + public String getNetworkDomain() { + return networkDomain; + } + + public long getParentDomainId() { + return parentDomainId; + } + + public String getParentDomainName() { + return parentDomainName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Domain domain = (Domain) o; + + if (hasChild != domain.hasChild) return false; + if (id != domain.id) return false; + if (level != domain.level) return false; + if (parentDomainId != domain.parentDomainId) return false; + if (name != null ? !name.equals(domain.name) : domain.name != null) + return false; + if (networkDomain != null ? !networkDomain.equals(domain.networkDomain) : domain.networkDomain != null) + return false; + if (parentDomainName != null ? !parentDomainName.equals(domain.parentDomainName) : domain.parentDomainName != null) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + (hasChild ? 1 : 0); + result = 31 * result + (int) (level ^ (level >>> 32)); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (networkDomain != null ? networkDomain.hashCode() : 0); + result = 31 * result + (int) (parentDomainId ^ (parentDomainId >>> 32)); + result = 31 * result + (parentDomainName != null ? parentDomainName.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Domain{" + + "id=" + id + + ", hasChild=" + hasChild + + ", level=" + level + + ", name='" + name + '\'' + + ", networkDomain='" + networkDomain + '\'' + + ", parentDomainId=" + parentDomainId + + ", parentDomainName='" + parentDomainName + '\'' + + '}'; + } + + @Override + public int compareTo(Domain arg0) { + return new Long(id).compareTo(arg0.getId()); + } + +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainAsyncClient.java new file mode 100644 index 0000000000..cbb620b94c --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainAsyncClient.java @@ -0,0 +1,83 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.features; + +import com.google.common.util.concurrent.ListenableFuture; +import org.jclouds.cloudstack.domain.Domain; +import org.jclouds.cloudstack.filters.QuerySigner; +import org.jclouds.cloudstack.options.ListDomainChildrenOptions; +import org.jclouds.cloudstack.options.ListDomainsOptions; +import org.jclouds.rest.annotations.ExceptionParser; +import org.jclouds.rest.annotations.OnlyElement; +import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.Set; + +/** + * Provides asynchronous access to CloudStack Domain features available to Domain + * Admin users. + * + * @author Andrei Savu + * @see + */ +@RequestFilters(QuerySigner.class) +@QueryParams(keys = "response", values = "json") +public interface DomainDomainAsyncClient { + + /** + * @see DomainDomainClient#listDomains + */ + @GET + @QueryParams(keys = "command", values = "listDomains") + @SelectJson("domain") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listDomains(ListDomainsOptions... options); + + /** + * @see DomainDomainClient#getDomainById + */ + @GET + @QueryParams(keys = "command", values = "listDomains") + @SelectJson("domain") + @OnlyElement + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getDomainById(@QueryParam("id") long domainId); + + /** + * @see DomainDomainClient#listDomainChildren + */ + @GET + @QueryParams(keys = "command", values = "listDomainChildren") + @SelectJson("domain") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listDomainChildren(ListDomainChildrenOptions... options); +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainClient.java new file mode 100644 index 0000000000..a2ae7ca5cc --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/DomainDomainClient.java @@ -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.cloudstack.features; + +import org.jclouds.cloudstack.domain.Domain; +import org.jclouds.cloudstack.options.ListDomainChildrenOptions; +import org.jclouds.cloudstack.options.ListDomainsOptions; +import org.jclouds.concurrent.Timeout; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Provides synchronous access to CloudStack Domain features available to Domain + * Admin users. + * + * @author Andrei Savu + * @see + */ +@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) +public interface DomainDomainClient { + + /** + * List domains with detailed information + * + * @param options + * list filtering optional arguments + * @return + * set of domain instances or empty + */ + Set listDomains(ListDomainsOptions... options); + + /** + * Get a domain by ID + * + * @param domainId + * domain ID + * @return + * domain instance or null + */ + Domain getDomainById(long domainId); + + /** + * Lists all children domains belonging to a specified domain + * + * @param options + * list filtering optional arguments + * @return + * set of domain instances or empty + */ + Set listDomainChildren(ListDomainChildrenOptions... options); +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainChildrenOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainChildrenOptions.java new file mode 100644 index 0000000000..1adcea6a7b --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainChildrenOptions.java @@ -0,0 +1,133 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Options used to control what domain children are returned + * + * @see + * @author Andrei Savu + */ +public class ListDomainChildrenOptions extends BaseHttpRequestOptions { + + public static final ListDomainChildrenOptions NONE = new ListDomainChildrenOptions(); + + /** + * @param parentDomainId + * firewall rule ID + */ + public ListDomainChildrenOptions parentDomainId(long parentDomainId) { + this.queryParameters.replaceValues("id", ImmutableSet.of(parentDomainId + "")); + return this; + } + + /** + * @param isRecursive + * to return the entire tree, use the value "true". To return + * the first level children, use the value "false". + */ + public ListDomainChildrenOptions isRecursive(boolean isRecursive) { + this.queryParameters.replaceValues("isrecursive", ImmutableSet.of(isRecursive + "")); + return this; + } + + /** + * @param keyword + * list by keyword + */ + public ListDomainChildrenOptions keyword(String keyword) { + this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword)); + return this; + } + + /** + * @param name + * list by domain name + */ + public ListDomainChildrenOptions name(String name) { + this.queryParameters.replaceValues("name", ImmutableSet.of(name)); + return this; + } + + public ListDomainChildrenOptions page(long page) { + this.queryParameters.replaceValues("page", ImmutableSet.of(page + "")); + return this; + } + + public ListDomainChildrenOptions pageSize(long pageSize) { + this.queryParameters.replaceValues("pagesize", ImmutableSet.of(pageSize + "")); + return this; + } + + public static class Builder { + + /** + * @see ListDomainChildrenOptions#parentDomainId + */ + public static ListDomainChildrenOptions parentDomainId(long parentDomainId) { + ListDomainChildrenOptions options = new ListDomainChildrenOptions(); + return options.parentDomainId(parentDomainId); + } + + /** + * @see ListDomainChildrenOptions#isRecursive + */ + public static ListDomainChildrenOptions isRecursive(boolean isRecursive) { + ListDomainChildrenOptions options = new ListDomainChildrenOptions(); + return options.isRecursive(isRecursive); + } + + /** + * @see ListDomainChildrenOptions#keyword + */ + public static ListDomainChildrenOptions keyword(String keyword) { + ListDomainChildrenOptions options = new ListDomainChildrenOptions(); + return options.keyword(keyword); + } + + /** + * @see ListDomainChildrenOptions#name + */ + public static ListDomainChildrenOptions name(String name) { + ListDomainChildrenOptions options = new ListDomainChildrenOptions(); + return options.name(name); + } + + /** + * @see ListDomainChildrenOptions#page + */ + public static ListDomainChildrenOptions page(long page) { + ListDomainChildrenOptions options = new ListDomainChildrenOptions(); + return options.page(page); + } + + /** + * @see ListDomainChildrenOptions#pageSize + */ + public static ListDomainChildrenOptions pageSize(long pageSize) { + ListDomainChildrenOptions options = new ListDomainChildrenOptions(); + return options.pageSize(pageSize); + } + } +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainsOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainsOptions.java new file mode 100644 index 0000000000..3b987df6ad --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListDomainsOptions.java @@ -0,0 +1,132 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Options used to control what domains are returned + * + * @see + * @author Andrei Savu + */ +public class ListDomainsOptions extends BaseHttpRequestOptions { + + public static final ListDomainsOptions NONE = new ListDomainsOptions(); + + /** + * @param id + * firewall rule ID + */ + public ListDomainsOptions id(long id) { + this.queryParameters.replaceValues("id", ImmutableSet.of(id + "")); + return this; + } + + /** + * @param keyword + * list by keyword + */ + public ListDomainsOptions keyword(String keyword) { + this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword)); + return this; + } + + /** + * @param level + * list by domain level + */ + public ListDomainsOptions level(long level) { + this.queryParameters.replaceValues("level", ImmutableSet.of(level + "")); + return this; + } + + /** + * @param name + * list by domain name + */ + public ListDomainsOptions name(String name) { + this.queryParameters.replaceValues("name", ImmutableSet.of(name)); + return this; + } + + public ListDomainsOptions page(long page) { + this.queryParameters.replaceValues("page", ImmutableSet.of(page + "")); + return this; + } + + public ListDomainsOptions pageSize(long pageSize) { + this.queryParameters.replaceValues("pagesize", ImmutableSet.of(pageSize + "")); + return this; + } + + public static class Builder { + + /** + * @see ListDomainsOptions#id + */ + public static ListDomainsOptions id(long id) { + ListDomainsOptions options = new ListDomainsOptions(); + return options.id(id); + } + + /** + * @see ListDomainsOptions#keyword + */ + public static ListDomainsOptions keyword(String keyword) { + ListDomainsOptions options = new ListDomainsOptions(); + return options.keyword(keyword); + } + + /** + * @see ListDomainsOptions#level + */ + public static ListDomainsOptions level(long level) { + ListDomainsOptions options = new ListDomainsOptions(); + return options.level(level); + } + + /** + * @see ListDomainsOptions#name + */ + public static ListDomainsOptions name(String name) { + ListDomainsOptions options = new ListDomainsOptions(); + return options.name(name); + } + + /** + * @see ListDomainsOptions#page + */ + public static ListDomainsOptions page(long page) { + ListDomainsOptions options = new ListDomainsOptions(); + return options.page(page); + } + + /** + * @see ListDomainsOptions#pageSize + */ + public static ListDomainsOptions pageSize(long pageSize) { + ListDomainsOptions options = new ListDomainsOptions(); + return options.pageSize(pageSize); + } + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientExpectTest.java new file mode 100644 index 0000000000..f47d03e03d --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientExpectTest.java @@ -0,0 +1,182 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.features; + +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.CloudStackContext; +import org.jclouds.cloudstack.domain.Account; +import org.jclouds.cloudstack.domain.Domain; +import org.jclouds.cloudstack.domain.User; +import org.jclouds.cloudstack.options.ListDomainChildrenOptions; +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.Set; + +import static org.jclouds.cloudstack.options.ListDomainChildrenOptions.Builder.parentDomainId; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +/** + * Test the CloudStack DomainDomainClient + * + * @author Andrei Savu + */ +@Test(groups = "unit", testName = "DomainDomainClientExpectTest") +public class DomainDomainClientExpectTest extends BaseCloudStackRestClientExpectTest { + + public void testListDomainsWhenResponseIs2xx() { + DomainDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listDomains&apiKey=identity&signature=MmzRB%2FpKlYyWy7kE3IMXrg4BUtk%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/listdomainsresponse.json")) + .build()); + + assertEquals(client.listDomains(), + ImmutableSet.of( + Domain.builder().id(1L).name("ROOT").level(0).hasChild(true).build(), + Domain.builder().id(2L).name("jclouds1").level(1).parentDomainId(1) + .parentDomainName("ROOT").hasChild(false).build() + )); + } + + public void testListDomainsWhenResponseIs404() { + DomainDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listDomains&apiKey=identity&signature=MmzRB%2FpKlYyWy7kE3IMXrg4BUtk%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()); + + assertEquals(client.listDomains(), ImmutableSet.of()); + } + + public void testGetDomainWhenResponseIs2xx() { + DomainDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listDomains&id=1&apiKey=identity&signature=emQKWkVhospRkaUzjKljME2rW0k%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/getdomainresponse.json")) + .build()); + + assertEquals(client.getDomainById(1), + Domain.builder().id(1L).name("ROOT").level(0).hasChild(true).build()); + } + + public void testGetDomainWhenResponseIs404() { + DomainDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listDomains&id=1&apiKey=identity&signature=emQKWkVhospRkaUzjKljME2rW0k%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()); + + assertNull(client.getDomainById(1)); + } + + public void testListDomainChildrenWhenResponseIs2xx() { + DomainDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listDomainChildren&id=1&isrecursive=true&apiKey=identity&signature=bDMSkjme8k0ANUPm4YiTYKe2N88%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/listdomainchildrenresponse.json")) + .build()); + + assertEquals(client.listDomainChildren(parentDomainId(1).isRecursive(true)), + ImmutableSet.of( + Domain.builder().id(2L).name("jclouds1").level(1).parentDomainId(1) + .parentDomainName("ROOT").hasChild(false).build(), + Domain.builder().id(3L).name("jclouds2").level(1).parentDomainId(1) + .parentDomainName("ROOT").hasChild(false).build() + )); + } + + public void testListDomainChildrenWhenResponseIs404() { + DomainDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listDomainChildren&id=1&isrecursive=true&apiKey=identity&" + + "signature=bDMSkjme8k0ANUPm4YiTYKe2N88%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()); + + assertEquals(client.listDomainChildren(parentDomainId(1).isRecursive(true)), ImmutableSet.of()); + } + + @Override + protected DomainDomainClient clientFrom(CloudStackContext context) { + return context.getDomainContext().getApi().getDomainClient(); + } +} \ No newline at end of file diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientLiveTest.java new file mode 100644 index 0000000000..553a563fc4 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/DomainDomainClientLiveTest.java @@ -0,0 +1,95 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.features; + +import com.google.common.base.Predicate; +import org.jclouds.cloudstack.domain.Domain; +import org.testng.annotations.Test; + +import javax.annotation.Nullable; +import java.util.Set; + +import static com.google.common.collect.Iterables.find; +import static org.jclouds.cloudstack.options.ListDomainChildrenOptions.Builder.parentDomainId; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +/** + * Tests behavior of {@code DomainDomainClient} + * + * @author Andrei Savu + */ +@Test(groups = "live", singleThreaded = true, testName = "DomainDomainClientLiveTest") +public class DomainDomainClientLiveTest extends BaseCloudStackClientLiveTest { + + @Test + public void testListDomains() { + assert domainAdminEnabled; + + Set allDomains = domainAdminClient.getDomainClient().listDomains(); + + Domain root = find(allDomains, withName("ROOT")); + assertEquals(root, domainAdminClient.getDomainClient().getDomainById(root.getId())); + assertEquals(root.getLevel(), 0); + assertEquals(root.getParentDomainId(), 0); + assertNull(root.getParentDomainName()); + if (allDomains.size() > 0) { + assertTrue(root.hasChild()); + } + + for (Domain domain : allDomains) { + checkDomain(domain, allDomains); + } + } + + @Test + public void testListDomainChildren() { + assert domainAdminEnabled; + + Set allDomains = domainAdminClient.getDomainClient().listDomains(); + Domain root = find(allDomains, withName("ROOT")); + + Set children = domainAdminClient.getDomainClient() + .listDomainChildren(parentDomainId(root.getId()).isRecursive(true)); + assertEquals(allDomains.size() - 1, children.size()); + + for (Domain domain : children) { + checkDomain(domain, allDomains); + } + } + + private Predicate withName(final String name) { + return new Predicate() { + @Override + public boolean apply(@Nullable Domain domain) { + return domain != null && domain.getName().equals(name); + } + }; + } + + private void checkDomain(Domain domain, Set allDomains) { + assert domain.getId() > 0 : domain; + if (domain.getParentDomainName() != null) { + Domain parent = find(allDomains, withName(domain.getParentDomainName())); + assertEquals(parent.getId(), domain.getParentDomainId()); + assertTrue(parent.hasChild()); + } + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListDomainsResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListDomainsResponseTest.java new file mode 100644 index 0000000000..f6fa41acd4 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListDomainsResponseTest.java @@ -0,0 +1,65 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.parse; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.jclouds.cloudstack.config.CloudStackParserModule; +import org.jclouds.cloudstack.domain.Domain; +import org.jclouds.json.BaseSetParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import java.util.Set; + +/** + * @author Andrei Savu + */ +@Test(groups = "unit") +public class ListDomainsResponseTest extends BaseSetParserTest { + + @Override + protected Injector injector() { + return Guice.createInjector(new CloudStackParserModule(), new GsonModule() { + @Override + protected void configure() { + bind(DateAdapter.class).to(Iso8601DateAdapter.class); + super.configure(); + } + }); + } + + @Override + public String resource() { + return "/listdomainsresponse.json"; + } + + @Override + @SelectJson("domain") + public Set expected() { + return ImmutableSet.of( + Domain.builder().id(1L).name("ROOT").level(0).hasChild(true).build(), + Domain.builder().id(2L).name("jclouds1").level(1).parentDomainId(1) + .parentDomainName("ROOT").hasChild(false).build() + ); + } + +} diff --git a/apis/cloudstack/src/test/resources/getdomainresponse.json b/apis/cloudstack/src/test/resources/getdomainresponse.json new file mode 100644 index 0000000000..a3baf5705a --- /dev/null +++ b/apis/cloudstack/src/test/resources/getdomainresponse.json @@ -0,0 +1,2 @@ +{ "listdomainsresponse" : { "count":1 ,"domain" : [ + {"id":1,"name":"ROOT","level":0,"haschild":true} ] } } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/listdomainchildrenresponse.json b/apis/cloudstack/src/test/resources/listdomainchildrenresponse.json new file mode 100644 index 0000000000..5cd2289bac --- /dev/null +++ b/apis/cloudstack/src/test/resources/listdomainchildrenresponse.json @@ -0,0 +1,3 @@ +{ "listdomainchildrenresponse" : { "count":2 ,"domain" : [ + {"id":2,"name":"jclouds1","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false}, + {"id":3,"name":"jclouds2","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} ] } } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/listdomainsresponse.json b/apis/cloudstack/src/test/resources/listdomainsresponse.json new file mode 100644 index 0000000000..79d7e00237 --- /dev/null +++ b/apis/cloudstack/src/test/resources/listdomainsresponse.json @@ -0,0 +1,3 @@ +{ "listdomainsresponse" : { "count":2 ,"domain" : [ + {"id":1,"name":"ROOT","level":0,"haschild":true}, + {"id":2,"name":"jclouds1","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} ] } } \ No newline at end of file From 23ce896dd2f4bb0ebbd81e9b9e43b562112967c1 Mon Sep 17 00:00:00 2001 From: andreisavu Date: Fri, 13 Jan 2012 17:37:25 +0200 Subject: [PATCH 47/82] Implemented Domain API for Global Admin --- .../CloudStackGlobalAsyncClient.java | 8 ++ .../cloudstack/CloudStackGlobalClient.java | 8 ++ .../config/CloudStackRestClientModule.java | 3 + .../features/GlobalDomainAsyncClient.java | 87 +++++++++++++++++++ .../features/GlobalDomainClient.java | 79 +++++++++++++++++ .../options/CreateDomainOptions.java | 75 ++++++++++++++++ .../options/UpdateDomainOptions.java | 72 +++++++++++++++ .../features/GlobalDomainClientLiveTest.java | 81 +++++++++++++++++ 8 files changed, 413 insertions(+) create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainAsyncClient.java create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainClient.java create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateDomainOptions.java create mode 100644 apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateDomainOptions.java create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java index b73d74a416..28f23cb064 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalAsyncClient.java @@ -23,6 +23,7 @@ import org.jclouds.cloudstack.features.GlobalAlertAsyncClient; import org.jclouds.cloudstack.features.GlobalCapacityAsyncClient; import org.jclouds.cloudstack.features.GlobalConfigurationAsyncClient; import org.jclouds.cloudstack.features.GlobalConfigurationClient; +import org.jclouds.cloudstack.features.GlobalDomainAsyncClient; import org.jclouds.cloudstack.features.GlobalHostAsyncClient; import org.jclouds.cloudstack.features.GlobalOfferingAsyncClient; import org.jclouds.cloudstack.features.GlobalStoragePoolAsyncClient; @@ -99,4 +100,11 @@ public interface CloudStackGlobalAsyncClient extends CloudStackDomainAsyncClient @Delegate @Override GlobalConfigurationAsyncClient getConfigurationClient(); + + /** + * Provides asynchronous access to Domain + */ + @Delegate + @Override + GlobalDomainAsyncClient getDomainClient(); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java index b6dc916c60..135a2cb755 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackGlobalClient.java @@ -24,6 +24,7 @@ import org.jclouds.cloudstack.features.GlobalAccountClient; import org.jclouds.cloudstack.features.GlobalAlertClient; import org.jclouds.cloudstack.features.GlobalCapacityClient; import org.jclouds.cloudstack.features.GlobalConfigurationClient; +import org.jclouds.cloudstack.features.GlobalDomainClient; import org.jclouds.cloudstack.features.GlobalHostClient; import org.jclouds.cloudstack.features.GlobalOfferingClient; import org.jclouds.cloudstack.features.GlobalStoragePoolClient; @@ -102,4 +103,11 @@ public interface CloudStackGlobalClient extends CloudStackDomainClient { @Delegate @Override GlobalConfigurationClient getConfigurationClient(); + + /** + * Provides synchronous access to Domain + */ + @Delegate + @Override + GlobalDomainClient getDomainClient(); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java index f4b060f2df..62d4b1b284 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java @@ -58,6 +58,8 @@ import org.jclouds.cloudstack.features.GlobalCapacityAsyncClient; import org.jclouds.cloudstack.features.GlobalCapacityClient; import org.jclouds.cloudstack.features.GlobalConfigurationAsyncClient; import org.jclouds.cloudstack.features.GlobalConfigurationClient; +import org.jclouds.cloudstack.features.GlobalDomainAsyncClient; +import org.jclouds.cloudstack.features.GlobalDomainClient; import org.jclouds.cloudstack.features.GlobalHostAsyncClient; import org.jclouds.cloudstack.features.GlobalHostClient; import org.jclouds.cloudstack.features.GlobalOfferingAsyncClient; @@ -147,6 +149,7 @@ public class CloudStackRestClientModule extends RestClientModule + */ +@RequestFilters(QuerySigner.class) +@QueryParams(keys = "response", values = "json") +public interface GlobalDomainAsyncClient extends DomainDomainAsyncClient { + + /** + * @see GlobalDomainClient#createDomain + */ + @GET + @QueryParams(keys = "command", values = "createDomain") + @SelectJson("domain") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture createDomain(@QueryParam("name") String name, CreateDomainOptions... options); + + /** + * @see GlobalDomainClient#updateDomain + */ + @GET + @QueryParams(keys = "command", values = "updateDomain") + @SelectJson("domain") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture updateDomain(@QueryParam("id") long domainId, UpdateDomainOptions... options); + + /** + * @see GlobalDomainClient#deleteOnlyDomain + */ + @GET + @QueryParams(keys = {"command", "cleanup"}, values = {"deleteDomain", "false"}) + @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + ListenableFuture deleteOnlyDomain(@QueryParam("id") long id); + + /** + * @see GlobalDomainClient#deleteDomainAndAttachedResources + */ + @GET + @QueryParams(keys = {"command", "cleanup"}, values = {"deleteDomain", "true"}) + @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + ListenableFuture deleteDomainAndAttachedResources(@QueryParam("id") long id); +} + diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainClient.java new file mode 100644 index 0000000000..9dd9099f43 --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/GlobalDomainClient.java @@ -0,0 +1,79 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.features; + +import org.jclouds.cloudstack.domain.Domain; +import org.jclouds.cloudstack.options.CreateDomainOptions; +import org.jclouds.cloudstack.options.UpdateDomainOptions; +import org.jclouds.concurrent.Timeout; + +import java.util.concurrent.TimeUnit; + +/** + * Provides synchronous access to CloudStack Domain features available to Global + * Admin users. + * + * @author Andrei Savu + * @see + */ +@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) +public interface GlobalDomainClient extends DomainDomainClient { + + /** + * Create new Domain + * + * @param name + * domain name + * @param options + * optional arguments + * @return + * domain instance + */ + Domain createDomain(String name, CreateDomainOptions... options); + + /** + * Update a domain + * + * @param domainId + * the ID of the domain + * @param options + * optional arguments + * @return + * domain instance + */ + Domain updateDomain(long domainId, UpdateDomainOptions... options); + + /** + * Delete domain (without deleting attached resources) + * + * @param id + * the domain ID + */ + Void deleteOnlyDomain(long id); + + /** + * Delete domain and cleanup all attached resources + * + * @param id + * the domain ID + */ + Void deleteDomainAndAttachedResources(long id); +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateDomainOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateDomainOptions.java new file mode 100644 index 0000000000..9012402b5b --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateDomainOptions.java @@ -0,0 +1,75 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; +import org.jclouds.http.options.BaseHttpRequestOptions; + +import java.util.Set; + +/** + * Options used to control how a domain is created + * + * @see + * @author Andrei Savu + */ +public class CreateDomainOptions extends BaseHttpRequestOptions { + + public static final CreateDomainOptions NONE = new CreateDomainOptions(); + + /** + * @param networkDomain + * network domain for networks in the domain + */ + public CreateDomainOptions networkDomain(String networkDomain) { + this.queryParameters.replaceValues("networkdomain", ImmutableSet.of(networkDomain)); + return this; + } + + /** + * @param parentDomainId + * the ID of the parent domain + */ + public CreateDomainOptions parentDomainId(long parentDomainId) { + this.queryParameters.replaceValues("parentdomainid", ImmutableSet.of(parentDomainId + "")); + return this; + } + + public static class Builder { + + /** + * @see CreateDomainOptions#networkDomain + */ + public static CreateDomainOptions networkDomain(String networkDomain) { + CreateDomainOptions options = new CreateDomainOptions(); + return options.networkDomain(networkDomain); + } + + /** + * @see CreateDomainOptions#parentDomainId + */ + public static CreateDomainOptions parentDomainId(long parentDomainId) { + CreateDomainOptions options = new CreateDomainOptions(); + return options.parentDomainId(parentDomainId); + } + } +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateDomainOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateDomainOptions.java new file mode 100644 index 0000000000..d7d972f460 --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/UpdateDomainOptions.java @@ -0,0 +1,72 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.options; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.http.options.BaseHttpRequestOptions; + +/** + * Options used to control how a domain is created + * + * @see + * @author Andrei Savu + */ +public class UpdateDomainOptions extends BaseHttpRequestOptions { + + public static final UpdateDomainOptions NONE = new UpdateDomainOptions(); + + /** + * @param name + * the new name for this domain + */ + public UpdateDomainOptions name(String name) { + this.queryParameters.replaceValues("name", ImmutableSet.of(name)); + return this; + } + + /** + * @param networkDomain + * network domain for networks in the domain + */ + public UpdateDomainOptions networkDomain(String networkDomain) { + this.queryParameters.replaceValues("networkdomain", ImmutableSet.of(networkDomain)); + return this; + } + + public static class Builder { + + /** + * @see UpdateDomainOptions#name + */ + public static UpdateDomainOptions name(String name) { + UpdateDomainOptions options = new UpdateDomainOptions(); + return options.name(name); + } + + /** + * @see UpdateDomainOptions#networkDomain + */ + public static UpdateDomainOptions networkDomain(String networkDomain) { + UpdateDomainOptions options = new UpdateDomainOptions(); + return options.networkDomain(networkDomain); + } + } +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java new file mode 100644 index 0000000000..b58376e911 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java @@ -0,0 +1,81 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.features; + +import com.google.common.base.Predicate; +import org.jclouds.cloudstack.domain.Domain; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import javax.annotation.Nullable; + +import static com.google.common.collect.Iterables.find; +import static org.jclouds.cloudstack.options.UpdateDomainOptions.Builder.name; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +/** + * Tests behavior of {@code GlobalDomainClient} + * + * @author Andrei Savu + */ +@Test(groups = "live", singleThreaded = true, testName = "GlobalDomainClientLiveTest") +public class GlobalDomainClientLiveTest extends BaseCloudStackClientLiveTest { + + private GlobalDomainClient domainClient; + private Domain rootDomain; + + @BeforeMethod + public void before() { + domainClient = globalAdminClient.getDomainClient(); + rootDomain = find(domainClient.listDomains(), new Predicate() { + @Override + public boolean apply(@Nullable Domain domain) { + return domain != null && domain.getName().equals("ROOT"); + } + }); + } + + @Test + public void testCreateAndUpdateDomain() { + assert globalAdminEnabled; + + Domain domain = null; + try { + domain = domainClient.createDomain(prefix + "-domain"); + checkDomain(domain, rootDomain, prefix + "-domain"); + + Domain updated = domainClient.updateDomain(domain.getId(), name(prefix + "-domain-2")); + checkDomain(updated, rootDomain, prefix + "-domain-2"); + assertEquals(updated.getId(), domain.getId()); + + } finally { + if (domain != null) { + domainClient.deleteDomainAndAttachedResources(domain.getId()); + } + } + assertNull(domainClient.getDomainById(domain.getId())); + } + + private void checkDomain(Domain domain, Domain rootDomain, String expectedName) { + assertEquals(domain.getParentDomainId(), rootDomain.getId()); + assertEquals(domain.getName(), expectedName); + assertEquals(domain.getParentDomainName(), rootDomain.getName()); + } +} From eb0e11689b15505561fe2e67364d235080f43fde Mon Sep 17 00:00:00 2001 From: andreisavu Date: Fri, 13 Jan 2012 22:02:27 +0200 Subject: [PATCH 48/82] Added expect tests for global domain client --- .../GlobalDomainClientExpectTest.java | 163 ++++++++++++++++++ .../features/GlobalDomainClientLiveTest.java | 2 +- .../test/resources/createdomainresponse.json | 2 + .../test/resources/deletedomainresponse.json | 1 + .../test/resources/updatedomainresponse.json | 2 + 5 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientExpectTest.java create mode 100644 apis/cloudstack/src/test/resources/createdomainresponse.json create mode 100644 apis/cloudstack/src/test/resources/deletedomainresponse.json create mode 100644 apis/cloudstack/src/test/resources/updatedomainresponse.json diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientExpectTest.java new file mode 100644 index 0000000000..4b3ecb8715 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientExpectTest.java @@ -0,0 +1,163 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.cloudstack.features; + +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import org.jclouds.cloudstack.CloudStackContext; +import org.jclouds.cloudstack.domain.Domain; +import org.jclouds.cloudstack.options.UpdateDomainOptions; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import java.net.URI; + +import static org.jclouds.cloudstack.options.ListDomainChildrenOptions.Builder.parentDomainId; +import static org.jclouds.cloudstack.options.UpdateDomainOptions.Builder.name; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +/** + * Test the CloudStack GlobalDomainClient + * + * @author Andrei Savu + */ +@Test(groups = "unit", testName = "GlobalDomainClientExpectTest") +public class GlobalDomainClientExpectTest extends BaseCloudStackRestClientExpectTest { + + public void testCreateDomainWhenResponseIs2xx() { + GlobalDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=createDomain&" + + "name=test&apiKey=identity&signature=6cxzEo7h63G0hgTTMLm4lGsSDK8%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/createdomainresponse.json")) + .build()); + + assertEquals(client.createDomain("test"), + Domain.builder().id(10L).name("test").level(1).parentDomainId(1L) + .parentDomainName("ROOT").hasChild(false).build()); + } + + public void testCreateDomainWhenResponseIs404() { + GlobalDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=createDomain&" + + "name=test&apiKey=identity&signature=6cxzEo7h63G0hgTTMLm4lGsSDK8%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()); + + assertNull(client.createDomain("test")); + } + + public void testUpdateDomainWhenResponseIs2xx() { + GlobalDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=updateDomain&id=10&name=test-2&apiKey=identity&signature=5t1eUf2Eyf%2FaB6qt%2BqIj%2BmcwFIo%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/updatedomainresponse.json")) + .build()); + + assertEquals(client.updateDomain(10, name("test-2")), + Domain.builder().id(10L).name("test-2").level(1).parentDomainId(1L) + .parentDomainName("ROOT").hasChild(false).build()); + } + + public void testUpdateDomainWhenResponseIs404() { + GlobalDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=updateDomain&id=10&name=test-2&apiKey=identity&signature=5t1eUf2Eyf%2FaB6qt%2BqIj%2BmcwFIo%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()); + + assertNull(client.updateDomain(10, name("test-2"))); + } + + public void testDeleteOnlyDomain() { + GlobalDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=deleteDomain&cleanup=false&id=1&apiKey=identity&signature=%2F5aLbigg612t9IrZi0JZO7CyiOU%3D")) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/deletedomainresponse.json")) + .build()); + + client.deleteOnlyDomain(1); + } + + public void testDeleteDomainAndAttachedResources() { + GlobalDomainClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=deleteDomain&cleanup=true&id=1&apiKey=identity&signature=grL7JStvtYUT89Jr0D8FgwMyJpU%3D")) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/deletedomainresponse.json")) + .build()); + + client.deleteDomainAndAttachedResources(1); + } + + @Override + protected GlobalDomainClient clientFrom(CloudStackContext context) { + return context.getGlobalContext().getApi().getDomainClient(); + } +} \ No newline at end of file diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java index b58376e911..d585ebef01 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalDomainClientLiveTest.java @@ -53,7 +53,7 @@ public class GlobalDomainClientLiveTest extends BaseCloudStackClientLiveTest { } @Test - public void testCreateAndUpdateDomain() { + public void testCreateUpdateDeleteDomain() { assert globalAdminEnabled; Domain domain = null; diff --git a/apis/cloudstack/src/test/resources/createdomainresponse.json b/apis/cloudstack/src/test/resources/createdomainresponse.json new file mode 100644 index 0000000000..c5882ab571 --- /dev/null +++ b/apis/cloudstack/src/test/resources/createdomainresponse.json @@ -0,0 +1,2 @@ +{ "createdomainresponse" : { "domain" : + {"id":10,"name":"test","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} } } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/deletedomainresponse.json b/apis/cloudstack/src/test/resources/deletedomainresponse.json new file mode 100644 index 0000000000..d617a158a2 --- /dev/null +++ b/apis/cloudstack/src/test/resources/deletedomainresponse.json @@ -0,0 +1 @@ +{ "deletedomainresponse" : {"jobid":2413} } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/updatedomainresponse.json b/apis/cloudstack/src/test/resources/updatedomainresponse.json new file mode 100644 index 0000000000..1745eacf94 --- /dev/null +++ b/apis/cloudstack/src/test/resources/updatedomainresponse.json @@ -0,0 +1,2 @@ +{ "updatedomainresponse" : { "domain" : + {"id":10,"name":"test-2","level":1,"parentdomainid":1,"parentdomainname":"ROOT","haschild":false} } } \ No newline at end of file From c395eb613e160f30b7fc667ed5a3d2af984e6665 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Fri, 13 Jan 2012 17:22:20 -0800 Subject: [PATCH 49/82] unused imports --- .../test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java index 8f6908eea4..bebe9c9ea5 100644 --- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java @@ -24,7 +24,6 @@ import static com.google.common.io.ByteStreams.toByteArray; import static org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions.Builder.storageClass; import static org.jclouds.crypto.CryptoStreams.md5; import static org.jclouds.io.Payloads.newByteArrayPayload; -import static org.jclouds.s3.domain.ObjectMetadata.StorageClass; import static org.jclouds.s3.options.ListBucketOptions.Builder.withPrefix; import static org.testng.Assert.assertEquals; @@ -35,8 +34,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.zip.GZIPInputStream; -import org.jclouds.aws.s3.blobstore.AWSS3BlobStore; -import org.jclouds.aws.s3.blobstore.options.AWSS3PutOptions; import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.KeyNotFoundException; import org.jclouds.blobstore.domain.Blob; @@ -50,7 +47,7 @@ import org.jclouds.s3.domain.ListBucketResponse; import org.jclouds.s3.domain.ObjectMetadata; import org.jclouds.s3.domain.ObjectMetadataBuilder; import org.jclouds.s3.domain.S3Object; -import org.jclouds.s3.options.ListBucketOptions; +import org.jclouds.s3.domain.ObjectMetadata.StorageClass; import org.testng.ITestContext; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; From 323303e9ab54bad353c5701b8ef6b551012c6e62 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Fri, 13 Jan 2012 17:22:31 -0800 Subject: [PATCH 50/82] clarified order in test --- .../handlers/RetryOnRenewExpectTest.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java b/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java index 44e4d6fba7..1f4d2ce184 100644 --- a/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java +++ b/apis/cloudservers/src/test/java/org/jclouds/cloudservers/handlers/RetryOnRenewExpectTest.java @@ -67,6 +67,19 @@ public class RetryOnRenewExpectTest extends BaseCloudServersRestClientExpectTest .put("Content-Length", "0") .build()).build(); + HttpRequest deleteImage = HttpRequest.builder().method("DELETE").endpoint( + URI.create("https://servers.api.rackspacecloud.com/v1.0/413274/images/11?now=1257695648897")).headers( + ImmutableMultimap. builder() + .put("X-Auth-Token", authToken).build()).build(); + + HttpResponse pleaseRenew = HttpResponse.builder().statusCode(401) + .message("HTTP/1.1 401 Unauthorized") + .payload(Payloads.newStringPayload("[{\"unauthorized\":{\"message\":\"Invalid authentication token. Please renew.\",\"code\":401}}]")) + .build(); + + // second auth uses same creds as initial one + HttpRequest redoAuth = initialAuth; + HttpResponse responseWithUrls2 = HttpResponse.builder().statusCode(204).message("HTTP/1.1 204 No Content") .headers(ImmutableMultimap.builder() .put("Server", "Apache/2.2.3 (Red Hat)") @@ -82,17 +95,7 @@ public class RetryOnRenewExpectTest extends BaseCloudServersRestClientExpectTest .put("X-CDN-Management-Url", "https://cdn1.clouddrive.com/v1/MossoCloudFS_dc1f419c-5059-4c87-a389-3f2e33a77b22") .put("Content-Length", "0") .build()).build(); - - HttpRequest deleteImage = HttpRequest.builder().method("DELETE").endpoint( - URI.create("https://servers.api.rackspacecloud.com/v1.0/413274/images/11?now=1257695648897")).headers( - ImmutableMultimap. builder() - .put("X-Auth-Token", authToken).build()).build(); - - HttpResponse pleaseRenew = HttpResponse.builder().statusCode(401) - .message("HTTP/1.1 401 Unauthorized") - .payload(Payloads.newStringPayload("[{\"unauthorized\":{\"message\":\"Invalid authentication token. Please renew.\",\"code\":401}}]")) - .build(); - + HttpRequest deleteImage2 = HttpRequest.builder().method("DELETE").endpoint( URI.create("https://servers.api.rackspacecloud.com/v1.0/413274/images/11?now=1257695648897")).headers( ImmutableMultimap. builder() @@ -101,7 +104,7 @@ public class RetryOnRenewExpectTest extends BaseCloudServersRestClientExpectTest HttpResponse imageDeleted = HttpResponse.builder().statusCode(204).message("HTTP/1.1 204 No Content").build(); CloudServersClient clientWhenImageExists = orderedRequestsSendResponses(initialAuth, responseWithUrls, - deleteImage, pleaseRenew, initialAuth, responseWithUrls2, deleteImage2, imageDeleted); + deleteImage, pleaseRenew, redoAuth, responseWithUrls2, deleteImage2, imageDeleted); assert clientWhenImageExists.deleteImage(11); } From f27bed524c51266da868266e55268a57156a073e Mon Sep 17 00:00:00 2001 From: andreisavu Date: Sat, 14 Jan 2012 00:32:35 +0200 Subject: [PATCH 51/82] Putting basic blocks in place for writing Expect tests for aws-s3 --- .../org/jclouds/s3/S3ClientExpectTest.java | 3 +- .../jclouds/aws/s3/AWSS3ClientExpectTest.java | 50 ++++++++++++++++ .../internal/BaseAWSS3ClientExpectTest.java | 57 +++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java create mode 100644 providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java diff --git a/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java b/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java index 4fb0c87186..ce237532dc 100644 --- a/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java +++ b/apis/s3/src/test/java/org/jclouds/s3/S3ClientExpectTest.java @@ -34,7 +34,8 @@ import com.google.common.collect.ImmutableMultimap; @Test(groups = "unit", testName = "S3ClientExpectTest") public class S3ClientExpectTest extends BaseS3ClientExpectTest { - public void bucketExistsReturnsTrueOn200AndFalseOn404() { + @Test + public void testBucketExistsReturnsTrueOn200AndFalseOn404() { HttpRequest bucketFooExists = HttpRequest.builder().method("HEAD").endpoint( URI.create("https://foo.s3.amazonaws.com/?max-keys=0")).headers( diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java new file mode 100644 index 0000000000..c5708087ec --- /dev/null +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java @@ -0,0 +1,50 @@ +/** + * 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.aws.s3; + +import org.jclouds.aws.s3.internal.BaseAWSS3ClientExpectTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import java.net.URI; + +import static org.jclouds.aws.s3.blobstore.options.AWSS3PutObjectOptions.Builder.storageClass; +import static org.jclouds.s3.domain.ObjectMetadata.StorageClass; + +/** + * @author Andrei Savu + */ +public class AWSS3ClientExpectTest extends BaseAWSS3ClientExpectTest { + + @Test + public void testPutWithReducedRedundancy() { + AWSS3Client client = requestSendsResponse( + HttpRequest.builder() + .method("PUT") + .endpoint(URI.create("http://test.s3.amazon.com/")) + .build(), + HttpResponse.builder() + .statusCode(200) + .build() + ); + + client.putObject("test", null, storageClass(StorageClass.REDUCED_REDUNDANCY)); + } +} diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java new file mode 100644 index 0000000000..511060586e --- /dev/null +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java @@ -0,0 +1,57 @@ +/** + * 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.aws.s3.internal; + +import com.google.common.base.Supplier; +import com.google.inject.Module; +import org.jclouds.aws.s3.AWSS3Client; +import org.jclouds.aws.s3.config.AWSS3RestClientModule; +import org.jclouds.date.TimeStamp; +import org.jclouds.http.RequiresHttp; +import org.jclouds.rest.BaseRestClientExpectTest; +import org.jclouds.rest.ConfiguresRestClient; + +/** + * Base class for writing Expect tests for AWS-S3 + * + * @author Andrei Savu + */ +public class BaseAWSS3ClientExpectTest extends BaseRestClientExpectTest { + + protected static final String CONSTANT_DATE = "2009-11-08T15:54:08.897Z"; + + public BaseAWSS3ClientExpectTest() { + provider = "aws-s3"; + } + + @RequiresHttp + @ConfiguresRestClient + private static final class TestAWSS3RestClientModule extends AWSS3RestClientModule { + @Override + protected String provideTimeStamp(@TimeStamp Supplier cache) { + return CONSTANT_DATE; + } + } + + @Override + protected Module createModule() { + return new TestAWSS3RestClientModule(); + } + +} From 20f5205727cbe1893a751cf20426a8b1b793cfc1 Mon Sep 17 00:00:00 2001 From: andreisavu Date: Sat, 14 Jan 2012 14:05:17 +0200 Subject: [PATCH 52/82] Added expect test for putBlob with reduced redundancy --- .../aws/s3/config/AWSS3RestClientModule.java | 14 ++++++++- .../jclouds/aws/s3/AWSS3ClientExpectTest.java | 31 +++++++++++++++++-- .../internal/BaseAWSS3ClientExpectTest.java | 26 ++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java index 138c3013f2..ccaf4b097b 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java @@ -33,6 +33,7 @@ import org.jclouds.aws.s3.binders.AssignCorrectHostnameAndBindAsHostPrefixIfConf import org.jclouds.http.RequiresHttp; import org.jclouds.location.Region; import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.RestContext; import org.jclouds.s3.Bucket; import org.jclouds.s3.S3AsyncClient; import org.jclouds.s3.S3Client; @@ -43,7 +44,7 @@ import com.google.inject.Provides; /** * Configures the S3 connection. - * + * * @author Adrian Cole */ @RequiresHttp @@ -84,4 +85,15 @@ public class AWSS3RestClientModule extends S3RestClientModule + */ + @SuppressWarnings("unchecked") + @Singleton + @Provides + RestContext + provideBaseContext(RestContext in) { + return (RestContext) in; + } + } diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java index c5708087ec..63055cb45f 100644 --- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientExpectTest.java @@ -18,9 +18,13 @@ */ package org.jclouds.aws.s3; +import com.google.common.collect.ImmutableMultimap; import org.jclouds.aws.s3.internal.BaseAWSS3ClientExpectTest; +import org.jclouds.blobstore.domain.Blob; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; +import org.jclouds.io.payloads.StringPayload; +import org.jclouds.s3.blobstore.functions.BlobToObject; import org.testng.annotations.Test; import java.net.URI; @@ -31,6 +35,7 @@ import static org.jclouds.s3.domain.ObjectMetadata.StorageClass; /** * @author Andrei Savu */ +@Test public class AWSS3ClientExpectTest extends BaseAWSS3ClientExpectTest { @Test @@ -38,13 +43,35 @@ public class AWSS3ClientExpectTest extends BaseAWSS3ClientExpectTest { AWSS3Client client = requestSendsResponse( HttpRequest.builder() .method("PUT") - .endpoint(URI.create("http://test.s3.amazon.com/")) + .endpoint(URI.create("https://test.s3.amazonaws.com/test")) + .headers(ImmutableMultimap.of( + "x-amz-storage-class", "REDUCED_REDUNDANCY", + "Host", "test.s3.amazonaws.com", + "Date", CONSTANT_DATE, + "Authorization", "AWS identity:1mJrW85/mqZpYTFIK5Ebtt2MM6E=" + )) + .payload(new StringPayload("content")) .build(), HttpResponse.builder() .statusCode(200) + .headers(ImmutableMultimap.of( + "x-amz-id-2", "w0rL+9fALQiCOToesVQefs8WalIgn+ZhMD7hHMKYud/xv7MyKkAWQOtFNEfK97Ri", + "x-amz-request-id", "7A84C3CD4437A4C0", + "Date", CONSTANT_DATE, + "ETag", "437b930db84b8079c2dd804a71936b5f", + "Server", "AmazonS3" + )) .build() ); - client.putObject("test", null, storageClass(StorageClass.REDUCED_REDUNDANCY)); + Blob blob = blobStore.blobBuilder("test").payload("content").build(); + BlobToObject blobToObject = getInstance(BlobToObject.class); + + client.putObject("test", blobToObject.apply(blob), + storageClass(StorageClass.REDUCED_REDUNDANCY)); + } + + public T getInstance(Class klass) { + return blobStoreContext.utils().injector().getInstance(klass); } } diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java index 511060586e..169b5d5962 100644 --- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/internal/BaseAWSS3ClientExpectTest.java @@ -18,15 +18,25 @@ */ package org.jclouds.aws.s3.internal; +import com.google.common.base.Function; import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; import com.google.inject.Module; import org.jclouds.aws.s3.AWSS3Client; import org.jclouds.aws.s3.config.AWSS3RestClientModule; +import org.jclouds.blobstore.BlobStore; +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.date.TimeStamp; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; import org.jclouds.http.RequiresHttp; +import org.jclouds.logging.config.NullLoggingModule; import org.jclouds.rest.BaseRestClientExpectTest; import org.jclouds.rest.ConfiguresRestClient; +import java.util.Properties; + /** * Base class for writing Expect tests for AWS-S3 * @@ -36,6 +46,9 @@ public class BaseAWSS3ClientExpectTest extends BaseRestClientExpectTest fn, Module module, Properties props) { + return clientFrom(BlobStoreContext.class.cast(new BlobStoreContextFactory(setupRestProperties()) + .createContext(provider, "identity", "credential", ImmutableSet.of(new ExpectModule(fn), + new NullLoggingModule(), module), props))); + } + + protected AWSS3Client clientFrom(BlobStoreContext context) { + blobStoreContext = context; + blobStore = context.getBlobStore(); + return AWSS3Client.class.cast(context.getProviderSpecificContext().getApi()); + } + } From 403aaa94b0b8b3ef839184681558053fb267298a Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 20:52:13 -0800 Subject: [PATCH 53/82] cleaned up and added test for TransformingSetSupplier --- .../collect/TransformingSetSupplier.java | 6 +- .../collect/TransformingSetSupplierTest.java | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/org/jclouds/collect/TransformingSetSupplierTest.java diff --git a/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java b/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java index 899b07c294..2010e8beaf 100644 --- a/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java +++ b/core/src/main/java/org/jclouds/collect/TransformingSetSupplier.java @@ -19,13 +19,15 @@ package org.jclouds.collect; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; -import static com.google.common.collect.Sets.newLinkedHashSet; import java.util.Set; import com.google.common.base.Function; import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; /** * @@ -42,7 +44,7 @@ public class TransformingSetSupplier implements Supplier> @Override public Set get() { - return newLinkedHashSet(transform(backingSupplier.get(), converter)); + return ImmutableSet.copyOf(filter(transform(filter(backingSupplier.get(), notNull()), converter), notNull())); } } diff --git a/core/src/test/java/org/jclouds/collect/TransformingSetSupplierTest.java b/core/src/test/java/org/jclouds/collect/TransformingSetSupplierTest.java new file mode 100644 index 0000000000..3b01670d3f --- /dev/null +++ b/core/src/test/java/org/jclouds/collect/TransformingSetSupplierTest.java @@ -0,0 +1,65 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.collect; + +import static org.testng.Assert.assertEquals; + +import java.util.List; + +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; + +/** + * + * @author Adrian Cole + */ +@Test(groups = "unit", singleThreaded = true, testName = "TransformingSetSupplierTest") +public class TransformingSetSupplierTest { + @Test + public void testTransform() { + TransformingSetSupplier supplier = new TransformingSetSupplier(Suppliers + .> ofInstance(ImmutableSet.of("foo")), Functions.forMap(ImmutableMap.of("foo", "bar"))); + assertEquals(supplier.get(), ImmutableSet. of("bar")); + } + + @Test + public void testNullsNotReturnedFromSourceSupplier() { + List ofNull = Lists.newArrayList(); + ofNull.add(null); + + TransformingSetSupplier supplier = new TransformingSetSupplier(Suppliers + .> ofInstance(ofNull), Functions.forMap(ImmutableMap.of("foo", "bar"))); + assertEquals(supplier.get(), ImmutableSet. of()); + } + + @SuppressWarnings("unchecked") + @Test + public void testNullsNotReturnedFromFunction() { + TransformingSetSupplier supplier = new TransformingSetSupplier(Suppliers + .> ofInstance(ImmutableSet.of("foo")), (Function) Functions.constant(null)); + assertEquals(supplier.get(), ImmutableSet. of()); + } + +} From ab6c4181bae984500831df6bc8c229b11efef0a1 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 20:53:49 -0800 Subject: [PATCH 54/82] Issue 710: our ovf classes currently do not support multiple virtual systems --- .../ovf/xml/internal/BaseEnvelopeHandler.java | 3 + .../jclouds/ovf/xml/EnvelopeHandlerTest.java | 22 +- compute/src/test/resources/ovf-vcd1.5.xml | 338 ++++++++++++++++++ 3 files changed, 359 insertions(+), 4 deletions(-) create mode 100644 compute/src/test/resources/ovf-vcd1.5.xml diff --git a/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java b/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java index 98406eddcf..6248658bc6 100644 --- a/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java +++ b/compute/src/main/java/org/jclouds/ovf/xml/internal/BaseEnvelopeHandler.java @@ -131,6 +131,9 @@ public class BaseEnvelopeHandler, B extends BaseV } else if (equalsOrSuffix(qName, "NetworkSection")) { inNetwork = false; builder.networkSection(networkHandler.getResult()); + } else if (equalsOrSuffix(qName, "VirtualSystemCollection")) { + // http://code.google.com/p/jclouds/issues/detail?id=811 + throw new IllegalArgumentException("this handler cannot currently create envelopes with multiple virtual systems"); } else if (equalsOrSuffix(qName, "VirtualSystem")) { inVirtualSystem = false; builder.virtualSystem(virtualSystemHandler.getResult()); diff --git a/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java b/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java index b2c657cb0d..19be6cdc40 100644 --- a/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java +++ b/compute/src/test/java/org/jclouds/ovf/xml/EnvelopeHandlerTest.java @@ -38,13 +38,27 @@ import com.google.inject.Injector; @Test(groups = "unit") public class EnvelopeHandlerTest { public void testVCloud1_0() { - InputStream is = getClass().getResourceAsStream("/ovf.xml"); - Injector injector = Guice.createInjector(new SaxParserModule()); - Factory factory = injector.getInstance(ParseSax.Factory.class); - Envelope result = factory.create(injector.getInstance(EnvelopeHandler.class)).parse(is); + Envelope result = parseEnvelope(); checkOvfEnvelope(result); } + public static Envelope parseEnvelope() { + InputStream is = EnvelopeHandlerTest.class.getResourceAsStream("/ovf.xml"); + Injector injector = Guice.createInjector(new SaxParserModule()); + Factory factory = injector.getInstance(ParseSax.Factory.class); + Envelope result = factory.create(injector.getInstance(EnvelopeHandler.class)).parse(is); + return result; + } + + //TODO: create a parser that can! + @Test(expectedExceptions = IllegalArgumentException.class) + public void testThrowIllegalArgumentAsWeDontYetSupportVirtualSystemCollections() { + InputStream is = getClass().getResourceAsStream("/ovf-vcd1.5.xml"); + Injector injector = Guice.createInjector(new SaxParserModule()); + Factory factory = injector.getInstance(ParseSax.Factory.class); + factory.create(injector.getInstance(EnvelopeHandler.class)).parse(is).getVirtualSystem(); + } + static void checkOvfEnvelope(Envelope result) { VirtualSystemSettingDataHandlerTest.checkVirtualSystem(result.getVirtualSystem()); } diff --git a/compute/src/test/resources/ovf-vcd1.5.xml b/compute/src/test/resources/ovf-vcd1.5.xml new file mode 100644 index 0000000000..d815e42786 --- /dev/null +++ b/compute/src/test/resources/ovf-vcd1.5.xml @@ -0,0 +1,338 @@ + + + + + The list of logical networks + + + + + + + + + The configuration parameters for logical networks + + + + + false + 192.168.2.1 + 255.255.255.0 + 109.233.48.141 + + + 192.168.2.100 + 192.168.2.199 + + + + isolated + + + false + 3600 + 7200 + + 192.168.2.2 + 192.168.2.99 + + + + + false + + + + + + true + 212.54.128.1 + 255.255.255.0 + 109.233.48.141 + 109.233.48.142 + + + 212.54.128.4 + 212.54.128.220 + + + + bridged + + + false + 3600 + 7200 + + 212.54.128.2 + 212.54.128.3 + + + + true + + + true + ipTranslation + allowTraffic + + + automatic + 72591b67-ea8f-4ae8-8a05-3e0a857d1e7b + 0 + + + + + + false + + + + Lease settings section + 0 + 0 + + + VApp template customization section + true + + + A collection of virtual machines: + Windows 2008 R2 Standard (base) no service pack + + VApp startup section + + + + + A virtual machine: Standard Edition + Windows 2008R2 Standard + + Specifies the operating system installed + Microsoft Windows Server 2008 R2 (64-bit) + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + Windows 2008R2 Standard + vmx-07 + + + 00:50:56:01:00:02 + 0 + true + StratoGen Ext Net + PCNet32 ethernet adapter + Network adapter 0 + 1 + PCNet32 + 10 + + + 0 + SCSI Controller + SCSI Controller 0 + 2 + lsilogicsas + 6 + + + 0 + Hard disk + Hard disk 1 + + 2000 + 2 + 17 + + + 0 + IDE Controller + IDE Controller 0 + 3 + 5 + + + 0 + false + CD/DVD Drive + CD/DVD Drive 1 + + 3000 + 3 + 15 + + + 0 + false + Floppy Drive + Floppy Drive 1 + + 8000 + 14 + + + hertz * 10^6 + Number of Virtual CPUs + 1 virtual CPU(s) + 4 + 0 + 3 + 1 + 0 + + + byte * 2^20 + Memory Size + 2048 MB of memory + 5 + 0 + 4 + 2048 + 0 + + + + Specifies the available VM network connections + 0 + + 0 + 212.54.128.101 + true + 00:50:56:01:00:02 + POOL + + + + Specifies Guest OS Customization Settings + true + true + false + false + true + true + 7qS$$3d# + false + WindowsServ-0 + + + + A virtual machine: Windows 2008 R2 Standard Edition[\r] + Windows 2008 R2 Standard (Base) NO SP1 + + Specifies the operating system installed + Microsoft Windows Server 2008 R2 (64-bit) + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + Windows 2008 R2 Standard (Base) NO SP1 + vmx-07 + + + 00:50:56:01:02:38 + 0 + true + int + PCNet32 ethernet adapter + Network adapter 0 + 1 + PCNet32 + 10 + + + 0 + SCSI Controller + SCSI Controller 0 + 2 + lsilogicsas + 6 + + + 0 + Hard disk + Hard disk 1 + + 2000 + 2 + 17 + + + 0 + IDE Controller + IDE Controller 0 + 3 + 5 + + + 0 + false + CD/DVD Drive + CD/DVD Drive 1 + + 3000 + 3 + 15 + + + 0 + false + Floppy Drive + Floppy Drive 1 + + 8000 + 14 + + + hertz * 10^6 + Number of Virtual CPUs + 1 virtual CPU(s) + 4 + 0 + 3 + 1 + 0 + + + byte * 2^20 + Memory Size + 2048 MB of memory + 5 + 0 + 4 + 2048 + 0 + + + + Specifies the available VM network connections + 0 + + 0 + 192.168.2.100 + true + 00:50:56:01:02:38 + POOL + + + + Specifies Guest OS Customization Settings + true + true + false + false + true + true + 4cV!Lunc + false + WindowsServer20 + + + + \ No newline at end of file From 72c1583ffd7e2f7c899ac92c159d51baf592dad7 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 20:54:35 -0800 Subject: [PATCH 55/82] allow validator to be used outside class hierarchy --- .../org/jclouds/predicates/validators/DnsNameValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java b/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java index 06fe2004fe..74db196c46 100644 --- a/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java +++ b/core/src/main/java/org/jclouds/predicates/validators/DnsNameValidator.java @@ -43,7 +43,7 @@ public class DnsNameValidator extends Validator { private int max; @Inject - protected DnsNameValidator(@Named("jclouds.dns_name_length_min") int min, + public DnsNameValidator(@Named("jclouds.dns_name_length_min") int min, @Named("jclouds.dns_name_length_max") int max) { this.min = min; this.max = max; From b3d6ad2ae8bd9a52d17d75cd61da283f95b0ec1e Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:02:52 -0800 Subject: [PATCH 56/82] Issue 812:add options to place xml source text to exception --- .../org/jclouds/http/functions/ParseSax.java | 61 +++++++++++++------ .../functions/config/SaxParserModule.java | 19 ++++-- .../src/test/resources/log4j.xml | 8 ++- .../src/test/resources/log4j.xml | 10 ++- 4 files changed, 71 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/org/jclouds/http/functions/ParseSax.java b/core/src/main/java/org/jclouds/http/functions/ParseSax.java index 6a6948c386..04f284fb42 100644 --- a/core/src/main/java/org/jclouds/http/functions/ParseSax.java +++ b/core/src/main/java/org/jclouds/http/functions/ParseSax.java @@ -21,18 +21,20 @@ package org.jclouds.http.functions; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.io.Closeables.closeQuietly; +import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; -import javax.inject.Inject; +import javax.annotation.Resource; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.logging.Logger; import org.jclouds.rest.InvocationContext; import org.jclouds.rest.internal.GeneratedHttpRequest; -import org.jclouds.util.Strings2; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; @@ -41,6 +43,7 @@ import org.xml.sax.helpers.DefaultHandler; import com.google.common.base.Function; import com.google.common.base.Throwables; +import com.google.common.io.Closeables; /** * This object will parse the body of an HttpResponse and return the result of type back to the @@ -50,6 +53,9 @@ import com.google.common.base.Throwables; */ public class ParseSax implements Function, InvocationContext> { + @Resource + private Logger logger = Logger.NULL; + private final XMLReader parser; private final HandlerWithResult handler; private HttpRequest request; @@ -58,7 +64,6 @@ public class ParseSax implements Function, InvocationContext ParseSax create(HandlerWithResult handler); } - @Inject public ParseSax(XMLReader parser, HandlerWithResult handler) { this.parser = checkNotNull(parser, "parser"); this.handler = checkNotNull(handler, "handler"); @@ -71,34 +76,45 @@ public class ParseSax implements Function, InvocationContext } catch (NullPointerException e) { return addDetailsAndPropagate(from, e); } - if (from.getStatusCode() >= 300) - return convertStreamToStringAndParse(from); - InputStream is = from.getPayload().getInput(); + InputStream is = null; try { + // debug is more normally set, so trace is more appropriate for + // something heavy like this + if (from.getStatusCode() >= 300 || logger.isTraceEnabled()) + return convertStreamToStringAndParse(from); + is = from.getPayload().getInput(); return parse(new InputSource(is)); } catch (RuntimeException e) { return addDetailsAndPropagate(from, e); } finally { - closeQuietly(is); + Closeables.closeQuietly(is); + from.getPayload().release(); } } - private T convertStreamToStringAndParse(HttpResponse from) { + private T convertStreamToStringAndParse(HttpResponse response) { + String from = null; try { - return parse(Strings2.toStringAndClose(from.getPayload().getInput())); + from = new String(closeClientButKeepContentStream(response)); + validateXml(from); + return doParse(new InputSource(new StringReader(from))); } catch (Exception e) { - return addDetailsAndPropagate(from, e); + return addDetailsAndPropagate(response, e, from); } } public T parse(String from) { try { - checkNotNull(from, "xml string"); - checkArgument(from.indexOf('<') >= 0, String.format("not an xml document [%s] ", from)); - } catch (RuntimeException e) { - return addDetailsAndPropagate(null, e); + validateXml(from); + return doParse(new InputSource(new StringReader(from))); + } catch (Exception e) { + return addDetailsAndPropagate(null, e, from); } - return parse(new InputSource(new StringReader(from))); + } + + private void validateXml(String from) { + checkNotNull(from, "xml string"); + checkArgument(from.indexOf('<') >= 0, String.format("not an xml document [%s] ", from)); } public T parse(InputStream from) { @@ -127,6 +143,10 @@ public class ParseSax implements Function, InvocationContext } public T addDetailsAndPropagate(HttpResponse response, Exception e) { + return addDetailsAndPropagate(response, e, null); + } + + public T addDetailsAndPropagate(HttpResponse response, Exception e, @Nullable String text) { StringBuilder message = new StringBuilder(); if (request != null) { message.append("request: ").append(request.getRequestLine()); @@ -144,15 +164,16 @@ public class ParseSax implements Function, InvocationContext } if (message.length() != 0) message.append("; "); - message.append(String.format("error at %d:%d in document %s", parseException.getColumnNumber(), - parseException.getLineNumber(), systemId)); + message.append(String.format("error at %d:%d in document %s", parseException.getColumnNumber(), parseException + .getLineNumber(), systemId)); } + if (text != null) + message.append("; source:\n").append(text); if (message.length() != 0) { message.append("; cause: ").append(e.toString()); throw new RuntimeException(message.toString(), e); } else { - Throwables.propagate(e); - return null; + throw Throwables.propagate(e); } } @@ -167,7 +188,7 @@ public class ParseSax implements Function, InvocationContext * @author Adrian Cole */ public abstract static class HandlerWithResult extends DefaultHandler implements - InvocationContext> { + InvocationContext> { private HttpRequest request; protected HttpRequest getRequest() { diff --git a/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java b/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java index 48625d0b49..9ea50891f3 100644 --- a/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java +++ b/core/src/main/java/org/jclouds/http/functions/config/SaxParserModule.java @@ -27,7 +27,9 @@ import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax.HandlerWithResult; import org.xml.sax.XMLReader; +import com.google.common.base.Throwables; import com.google.inject.AbstractModule; +import com.google.inject.Injector; import com.google.inject.Provides; import com.google.inject.Scopes; @@ -42,18 +44,27 @@ public class SaxParserModule extends AbstractModule { bind(ParseSax.Factory.class).to(Factory.class).in(Scopes.SINGLETON); } - private static class Factory implements ParseSax.Factory { + static class Factory implements ParseSax.Factory { + private final SAXParserFactory factory; + private final Injector i; + @Inject - private SAXParserFactory factory; + Factory(SAXParserFactory factory, Injector i) { + this.factory = factory; + this.i = i; + } public ParseSax create(HandlerWithResult handler) { SAXParser saxParser; try { saxParser = factory.newSAXParser(); XMLReader parser = saxParser.getXMLReader(); - return new ParseSax(parser, handler); + // TODO: switch to @AssistedInject + ParseSax returnVal = new ParseSax(parser, handler); + i.injectMembers(returnVal); + return returnVal; } catch (Exception e) { - throw new RuntimeException(e); + throw Throwables.propagate(e); } } diff --git a/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml b/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml index 63810d3ca0..daefa0e832 100644 --- a/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml +++ b/providers/greenhousedata-element-vcloud/src/test/resources/log4j.xml @@ -120,7 +120,13 @@ - + + + + + + + diff --git a/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml b/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml index 63810d3ca0..a301f89d1a 100644 --- a/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml +++ b/providers/stratogen-vcloud-mycloud/src/test/resources/log4j.xml @@ -120,7 +120,13 @@ - + + + + + + + @@ -132,7 +138,7 @@ - + From a28a981931259169f6b8dbf491ae3ac38c091db4 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:06:05 -0800 Subject: [PATCH 57/82] address case when curl is not yet installed --- .../test/java/org/jclouds/compute/RunScriptData.java | 11 ++++++++--- compute/src/test/resources/initscript_with_java.sh | 4 ++-- compute/src/test/resources/initscript_with_jboss.sh | 4 ++-- compute/src/test/resources/runscript.sh | 4 ++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/compute/src/test/java/org/jclouds/compute/RunScriptData.java b/compute/src/test/java/org/jclouds/compute/RunScriptData.java index 8aa5cc8507..d2eafcdfc3 100644 --- a/compute/src/test/java/org/jclouds/compute/RunScriptData.java +++ b/compute/src/test/java/org/jclouds/compute/RunScriptData.java @@ -149,18 +149,23 @@ public class RunScriptData { public static String aptInstall = "apt-get install -f -y -qq --force-yes"; + public static String aptInstallLazyUpgrade(String packageName) { + return aptInstall + " " + packageName + "|| (" + "apt-get update -qq&&" + "apt-get upgrade -y -qq" + ")&&" + + aptInstall + " " + packageName; + } + public static final Statement APT_RUN_SCRIPT = newStatementList(// + exec("which nslookup >&- 2>&-|| " + aptInstallLazyUpgrade("dnsutils")),// normalizeHostAndDNSConfig(),// - exec("which curl >&- 2>&-|| " + aptInstall + " curl"),// - exec("which nslookup >&- 2>&-|| " + aptInstall + " dnsutils"),// + exec("which curl >&- 2>&-|| " + aptInstallLazyUpgrade("curl")),// JDK7_INSTALL_TGZ); public static String yumInstall = "yum --nogpgcheck -y install"; public static final Statement YUM_RUN_SCRIPT = newStatementList(// + exec("which nslookup >&- 2>&-|| " + yumInstall + " bind-utils"),// normalizeHostAndDNSConfig(),// exec("which curl >&- 2>&-|| " + yumInstall + " curl"),// - exec("which nslookup >&- 2>&-|| " + yumInstall + " bind-utils"),// JDK7_INSTALL_TGZ); public static final Statement ZYPPER_RUN_SCRIPT = newStatementList(// diff --git a/compute/src/test/resources/initscript_with_java.sh b/compute/src/test/resources/initscript_with_java.sh index 898ff2455f..b0494d5e69 100644 --- a/compute/src/test/resources/initscript_with_java.sh +++ b/compute/src/test/resources/initscript_with_java.sh @@ -99,10 +99,10 @@ PermitRootLogin no /etc/init.d/sshd reload||/etc/init.d/ssh reload awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow +which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf -which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl -which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils +which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl mkdir -p /usr/local/jdk curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) mv /usr/local/jdk1.7*/* /usr/local/jdk/ diff --git a/compute/src/test/resources/initscript_with_jboss.sh b/compute/src/test/resources/initscript_with_jboss.sh index 5ffab24c6b..c9ea3f34e5 100644 --- a/compute/src/test/resources/initscript_with_jboss.sh +++ b/compute/src/test/resources/initscript_with_jboss.sh @@ -99,10 +99,10 @@ PermitRootLogin no /etc/init.d/sshd reload||/etc/init.d/ssh reload awk -v user=^${SUDO_USER:=${USER}}: -v password='crypt(randompassword)' 'BEGIN { FS=OFS=":" } $0 ~ user { $2 = password } 1' /etc/shadow >/etc/shadow.${SUDO_USER:=${USER}} test -f /etc/shadow.${SUDO_USER:=${USER}} && mv /etc/shadow.${SUDO_USER:=${USER}} /etc/shadow +which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf -which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl -which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils +which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl mkdir -p /usr/local/jdk curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) mv /usr/local/jdk1.7*/* /usr/local/jdk/ diff --git a/compute/src/test/resources/runscript.sh b/compute/src/test/resources/runscript.sh index 2d247070a4..d20f61a84d 100644 --- a/compute/src/test/resources/runscript.sh +++ b/compute/src/test/resources/runscript.sh @@ -78,10 +78,10 @@ END_OF_SCRIPT # add desired commands from the user cat >> $INSTANCE_HOME/runScriptWithCreds.sh <<'END_OF_SCRIPT' cd $INSTANCE_HOME +which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes dnsutils grep `hostname` /etc/hosts >/dev/null || awk -v hostname=`hostname` 'END { print $1" "hostname }' /proc/net/arp >> /etc/hosts nslookup yahoo.com >/dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf -which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl -which nslookup >&- 2>&-|| apt-get install -f -y -qq --force-yes dnsutils +which curl >&- 2>&-|| apt-get install -f -y -qq --force-yes curl|| (apt-get update -qq&&apt-get upgrade -y -qq)&&apt-get install -f -y -qq --force-yes curl mkdir -p /usr/local/jdk curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.tar.gz |(mkdir -p /usr/local &&cd /usr/local &&tar -xpzf -) mv /usr/local/jdk1.7*/* /usr/local/jdk/ From bc172850c140c0377fa271f9008456285326b8b7 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:06:32 -0800 Subject: [PATCH 58/82] retry sftp failures --- .../src/main/java/org/jclouds/sshj/SshjSshClient.java | 5 ++++- .../src/test/java/org/jclouds/sshj/SshjSshClientTest.java | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java b/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java index 9427141944..1d55a8c14a 100644 --- a/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java +++ b/drivers/sshj/src/main/java/org/jclouds/sshj/SshjSshClient.java @@ -46,6 +46,7 @@ import net.schmizz.sshj.connection.ConnectionException; import net.schmizz.sshj.connection.channel.direct.Session; import net.schmizz.sshj.connection.channel.direct.Session.Command; import net.schmizz.sshj.sftp.SFTPClient; +import net.schmizz.sshj.sftp.SFTPException; import net.schmizz.sshj.transport.TransportException; import net.schmizz.sshj.transport.verification.PromiscuousVerifier; import net.schmizz.sshj.userauth.UserAuthException; @@ -122,7 +123,9 @@ public class SshjSshClient implements SshClient { // NOTE cannot retry io exceptions, as SSHException is a part of the chain private Predicate retryPredicate = or(instanceOf(ConnectionException.class), instanceOf(ConnectException.class), instanceOf(SocketTimeoutException.class), - instanceOf(TransportException.class)); + instanceOf(TransportException.class), + // safe to retry sftp exceptions as they are idempotent + instanceOf(SFTPException.class)); @Resource @Named("jclouds.ssh") diff --git a/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java b/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java index 08d4b5e9dd..44a744bb82 100644 --- a/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java +++ b/drivers/sshj/src/test/java/org/jclouds/sshj/SshjSshClientTest.java @@ -19,11 +19,11 @@ package org.jclouds.sshj; import static com.google.inject.name.Names.bindProperties; +import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.classextension.EasyMock.createMock; -import static org.easymock.classextension.EasyMock.replay; -import static org.easymock.classextension.EasyMock.verify; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; import java.io.IOException; import java.net.ConnectException; @@ -34,6 +34,7 @@ import java.util.logging.Level; import net.schmizz.sshj.SSHClient; import net.schmizz.sshj.common.SSHException; import net.schmizz.sshj.connection.ConnectionException; +import net.schmizz.sshj.sftp.SFTPException; import net.schmizz.sshj.transport.TransportException; import net.schmizz.sshj.userauth.UserAuthException; @@ -99,6 +100,7 @@ public class SshjSshClientTest { public void testExceptionClassesRetry() { assert ssh.shouldRetry(new ConnectionException("Read timed out", new SSHException("Read timed out", new SocketTimeoutException("Read timed out")))); + assert ssh.shouldRetry(new SFTPException("Failure!")); assert ssh.shouldRetry(new SocketTimeoutException("connect timed out")); assert ssh.shouldRetry(new TransportException("socket closed")); assert ssh.shouldRetry(new ConnectionException("problem")); From 7e32b0624daf142edd5928cf189c1fd920082858 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:07:39 -0800 Subject: [PATCH 59/82] add reminder to add exception to this method, so that we can cleanup stale resources --- .../main/java/org/jclouds/compute/ComputeServiceAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java b/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java index 4101128319..a9fa7e71b8 100644 --- a/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java +++ b/compute/src/main/java/org/jclouds/compute/ComputeServiceAdapter.java @@ -58,7 +58,7 @@ public interface ComputeServiceAdapter { * includes {@code imageId}, {@code locationId}, and * {@code hardwareId} used to resume the instance. * @return library-native representation of a node. - * + * TODO: return typed exception on createNodeFailure * @see ComputeService#createNodesInGroup(String, int, Template) */ NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String tag, String name, Template template); From 9d36c3e4b01efa81046875a59bb906551ca42d02 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:11:22 -0800 Subject: [PATCH 60/82] renamed tag -> group removed old language in exception about tag --- .../jclouds/compute/RunNodesException.java | 14 +++---- ...sWithGroupEncodedIntoNameThenAddToSet.java | 40 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/compute/src/main/java/org/jclouds/compute/RunNodesException.java b/compute/src/main/java/org/jclouds/compute/RunNodesException.java index 6c809ad305..d6e73d1074 100644 --- a/compute/src/main/java/org/jclouds/compute/RunNodesException.java +++ b/compute/src/main/java/org/jclouds/compute/RunNodesException.java @@ -35,26 +35,26 @@ public class RunNodesException extends Exception { /** The serialVersionUID */ private static final long serialVersionUID = -2272965726680821281L; - private final String tag; + private final String group; private final int count; private final Template template; private final Set successfulNodes; private final Map failedNodes; private final Map executionExceptions; - public RunNodesException(String tag, int count, Template template, + public RunNodesException(String group, int count, Template template, Set successfulNodes, Map executionExceptions, Map failedNodes) { super( String .format( - "error running %d node%s tag(%s) location(%s) image(%s) size(%s) options(%s)%n%s%n%s", - count, count > 1 ? "s" : "", tag, template.getLocation().getId(), + "error running %d node%s group(%s) location(%s) image(%s) size(%s) options(%s)%n%s%n%s", + count, count > 1 ? "s" : "", group, template.getLocation().getId(), template.getImage().getProviderId(), template.getHardware() .getProviderId(), template.getOptions(), createExecutionErrorMessage(executionExceptions), createNodeErrorMessage(failedNodes))); - this.tag = tag; + this.group = group; this.count = count; this.template = template; this.successfulNodes = successfulNodes; @@ -86,8 +86,8 @@ public class RunNodesException extends Exception { return failedNodes; } - public String getTag() { - return tag; + public String getGroup() { + return group; } public int getCount() { diff --git a/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java index 900107431e..a1f1a80013 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/impl/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java @@ -62,12 +62,12 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo private class AddNode implements Callable { private final String name; - private final String tag; + private final String group; private final Template template; - private AddNode(String name, String tag, Template template) { + private AddNode(String name, String group, Template template) { this.name = checkNotNull(name, "name"); - this.tag = checkNotNull(tag, "tag"); + this.group = checkNotNull(group, "group"); this.template = checkNotNull(template, "template"); } @@ -77,13 +77,13 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo logger.debug(">> adding node location(%s) name(%s) image(%s) hardware(%s)", template.getLocation().getId(), name, template.getImage().getProviderId(), template.getHardware() .getProviderId()); - node = addNodeWithTagStrategy.createNodeWithGroupEncodedIntoName(tag, name, template); + node = addNodeWithGroupStrategy.createNodeWithGroupEncodedIntoName(group, name, template); logger.debug("<< %s node(%s)", node.getState(), node.getId()); return node; } public String toString() { - return toStringHelper(this).add("name", name).add("tag", tag).add("template", template).toString(); + return toStringHelper(this).add("name", name).add("group", group).add("template", template).toString(); } } @@ -91,7 +91,7 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - protected final CreateNodeWithGroupEncodedIntoName addNodeWithTagStrategy; + protected final CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy; protected final ListNodesStrategy listNodesStrategy; protected final String nodeNamingConvention; protected final ExecutorService executor; @@ -99,12 +99,12 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo @Inject protected CreateNodesWithGroupEncodedIntoNameThenAddToSet( - CreateNodeWithGroupEncodedIntoName addNodeWithTagStrategy, + CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, ListNodesStrategy listNodesStrategy, @Named("NAMING_CONVENTION") String nodeNamingConvention, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory) { - this.addNodeWithTagStrategy = addNodeWithTagStrategy; + this.addNodeWithGroupStrategy = addNodeWithGroupStrategy; this.listNodesStrategy = listNodesStrategy; this.nodeNamingConvention = nodeNamingConvention; this.executor = executor; @@ -112,15 +112,15 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo } /** - * This implementation gets a list of acceptable node names to encode the tag into, then it + * This implementation gets a list of acceptable node names to encode the group into, then it * simultaneously runs the nodes and applies options to them. */ @Override - public Map> execute(String tag, int count, Template template, Set goodNodes, + public Map> execute(String group, int count, Template template, Set goodNodes, Map badNodes, Multimap customizationResponses) { Map> responses = newLinkedHashMap(); - for (String name : getNextNames(tag, template, count)) { - responses.put(name, compose(executor.submit(new AddNode(name, tag, template)), + for (String name : getNextNames(group, template, count)) { + responses.put(name, compose(executor.submit(new AddNode(name, group, template)), customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory.create(template.getOptions(), goodNodes, badNodes, customizationResponses), executor)); } @@ -128,22 +128,22 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo } /** - * Find the next node names that can be used. These will be derived from the tag and the + * Find the next node names that can be used. These will be derived from the group and the * template. We will pre-allocate a specified quantity, and attempt to verify that there is no * name conflict with the current service. * - * @param tag + * @param group * @param count * @param template * @return */ - protected Set getNextNames(final String tag, final Template template, int count) { + protected Set getNextNames(final String group, final Template template, int count) { Set names = newLinkedHashSet(); Iterable currentNodes = listNodesStrategy.listNodes(); int maxTries = 100; int currentTries = 0; while (names.size() < count && currentTries++ < maxTries) { - final String name = getNextName(tag, template); + final String name = getNextName(group, template); if (!any(currentNodes, new Predicate() { @Override @@ -159,14 +159,14 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo } /** - * Get a name using a random mechanism that still ties all nodes in a tag together. + * Get a name using a random mechanism that still ties all nodes in a group together. * - * This implementation will pass the tag and a hex formatted random number to the configured + * This implementation will pass the group and a hex formatted random number to the configured * naming convention. * */ - protected String getNextName(final String tag, final Template template) { - return String.format(nodeNamingConvention, tag, Integer.toHexString(new SecureRandom().nextInt(4095))); + protected String getNextName(final String group, final Template template) { + return String.format(nodeNamingConvention, group, Integer.toHexString(new SecureRandom().nextInt(4095))); } } \ No newline at end of file From c9f980e59ed61bc4837b57f977454e9d4c4e27cd Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:09:12 -0800 Subject: [PATCH 61/82] filtered out null objects --- .../ComputeServiceAdapterContextModule.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java index a225389b3e..8321e094c4 100644 --- a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java +++ b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java @@ -18,6 +18,11 @@ */ package org.jclouds.compute.config; +import static com.google.common.base.Functions.compose; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Iterables.transform; +import static com.google.inject.util.Types.newParameterizedType; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import java.util.Set; @@ -48,14 +53,11 @@ import org.jclouds.domain.LoginCredentials; import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; import com.google.common.base.Function; -import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; -import com.google.inject.util.Types; /** * @@ -77,8 +79,8 @@ public class ComputeServiceAdapterContextModule extends BaseCo super.configure(); bind(new TypeLiteral() { }).to( - (TypeLiteral) TypeLiteral.get(Types.newParameterizedType(ComputeServiceContextImpl.class, - syncClientType, asyncClientType))).in(Scopes.SINGLETON); + (TypeLiteral) TypeLiteral.get(newParameterizedType(ComputeServiceContextImpl.class, syncClientType, + asyncClientType))).in(Scopes.SINGLETON); } @Override @@ -95,7 +97,8 @@ public class ComputeServiceAdapterContextModule extends BaseCo seconds, new Supplier>() { @Override public Set get() { - return ImmutableSet. copyOf(Iterables.transform(adapter.listLocations(), transformer)); + return ImmutableSet. copyOf(transform(filter(adapter.listLocations(), notNull()), + transformer)); } }); } @@ -108,7 +111,7 @@ public class ComputeServiceAdapterContextModule extends BaseCo @Override public Iterable get() { - return adapter.listHardwareProfiles(); + return filter(adapter.listHardwareProfiles(), notNull()); } }, transformer); @@ -122,10 +125,10 @@ public class ComputeServiceAdapterContextModule extends BaseCo @Override public Iterable get() { - return adapter.listImages(); + return filter(adapter.listImages(), notNull()); } - }, Functions.compose(addDefaultCredentialsToImage, transformer)); + }, compose(addDefaultCredentialsToImage, transformer)); } @Singleton @@ -139,6 +142,8 @@ public class ComputeServiceAdapterContextModule extends BaseCo @Override public Image apply(Image arg0) { + if (arg0 == null) + return null; LoginCredentials credentials = credsForImage.apply(arg0); return credentials != null ? ImageBuilder.fromImage(arg0).defaultCredentials(credentials).build() : arg0; } From 9791a510393d0add19968bbb3aff6ebc3338bfac Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:09:49 -0800 Subject: [PATCH 62/82] better exception message remoced unused import removed hokey test --- .../strategy/impl/ReturnCredentialsBoundToImage.java | 3 ++- core/src/test/java/org/jclouds/util/Suppliers2Test.java | 1 - .../jclouds/aws/ec2/services/AWSAMIClientLiveTest.java | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java b/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java index 5eae2555ea..0d58fbe648 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/impl/ReturnCredentialsBoundToImage.java @@ -51,7 +51,8 @@ public class ReturnCredentialsBoundToImage implements PopulateDefaultLoginCreden @Override public LoginCredentials apply(Object resourceToAuthenticate) { - checkState(resourceToAuthenticate instanceof Image, "this is only valid for images"); + checkState(resourceToAuthenticate instanceof Image, "this is only valid for images, not %s", + resourceToAuthenticate.getClass().getSimpleName()); if (creds != null) return creds; Image image = Image.class.cast(resourceToAuthenticate); diff --git a/core/src/test/java/org/jclouds/util/Suppliers2Test.java b/core/src/test/java/org/jclouds/util/Suppliers2Test.java index 931945129f..41c669de3f 100644 --- a/core/src/test/java/org/jclouds/util/Suppliers2Test.java +++ b/core/src/test/java/org/jclouds/util/Suppliers2Test.java @@ -37,7 +37,6 @@ import org.testng.annotations.Test; import com.google.common.base.Function; import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; public class Suppliers2Test { diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java index ebeeb4c6b8..630b2d5ba3 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/AWSAMIClientLiveTest.java @@ -190,14 +190,14 @@ public class AWSAMIClientLiveTest extends BaseVersionedServiceLiveTest { // TODO client.resetLaunchPermissionsOnImageInRegion(null, imageId); } - @Test(expectedExceptions = AuthorizationException.class) + @Test(enabled = false) public void testGetLaunchPermissionForImage() { - System.out.println(client.getLaunchPermissionForImageInRegion(null, imageId)); + // TODO System.out.println(client.getLaunchPermissionForImageInRegion(null, imageId)); } - @Test(expectedExceptions = AuthorizationException.class) + @Test(enabled = false) public void testGetProductCodesForImage() { - System.out.println(client.getProductCodesForImageInRegion(null, imageId)); + // TODO System.out.println(client.getProductCodesForImageInRegion(null, imageId)); } @Test(enabled = false) From 16a973c08c17b283a819fd01e26b467ddd03ba21 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:10:52 -0800 Subject: [PATCH 63/82] handle case when image location is null (ex. not scoped to a location) work on templates where image and hardware have no location better warning messages on templates we cannot use lookup images less often in vcloud --- .../internal/EC2TemplateBuilderImplTest.java | 7 + .../vcloud/VCloudPropertiesBuilder.java | 3 +- ...velopeOrThrowIllegalArgumentException.java | 78 +++++++++++ .../strategy/VCloudComputeServiceAdapter.java | 21 ++- .../domain/internal/TemplateBuilderImpl.java | 127 +++++++++++++----- .../internal/TemplateBuilderImplTest.java | 111 +++++++++++++-- 6 files changed, 297 insertions(+), 50 deletions(-) create mode 100644 apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java index f17f70e913..055028e51d 100644 --- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java +++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/EC2TemplateBuilderImplTest.java @@ -93,7 +93,14 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest { return new EC2TemplateBuilderImpl(locations, images, sizes, Suppliers.ofInstance(defaultLocation), optionsProvider, templateBuilderProvider, Suppliers.>ofInstance(imageMap)); } + + @Override + @Test + public void testHardwareWithImageIdPredicateOnlyAcceptsImageWhenLocationNull() { + // not possible to have null region in ec2 + } + @SuppressWarnings("unchecked") @Test public void testParseOnDemand() { diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java index e28babcf2e..c24533e0b5 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudPropertiesBuilder.java @@ -49,7 +49,8 @@ public class VCloudPropertiesBuilder extends PropertiesBuilder { properties.setProperty(PROPERTY_VCLOUD_DEFAULT_FENCEMODE, FenceMode.BRIDGED.toString()); // TODO integrate this with the {@link ComputeTimeouts} instead of having a single timeout for // everything. - properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 600l * 1000l + ""); + properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 1200l * 1000l + ""); + properties.setProperty(PROPERTY_SESSION_INTERVAL, 300 + ""); return properties; } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java new file mode 100644 index 0000000000..b7cebb5964 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java @@ -0,0 +1,78 @@ +/** + * 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.vcloud.compute.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; +import java.util.concurrent.ExecutionException; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.ovf.Envelope; +import org.jclouds.vcloud.domain.VAppTemplate; + +import com.google.common.base.Function; +import com.google.common.cache.LoadingCache; + +/** + * @author Adrian Cole + */ +@Singleton +public class ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException implements + Function { + + @Resource + protected Logger logger = Logger.NULL; + + private final LoadingCache envelopes; + + @Inject + protected ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException(LoadingCache envelopes) { + this.envelopes = checkNotNull(envelopes, "envelopes"); + } + + @Override + public Envelope apply(VAppTemplate from) { + checkArgument(from.getChildren().size() == 1, "multiple vms are not supported: %s", from); + + checkArgument(from.getNetworkSection().getNetworks().size() == 1, + "multiple network connections are not supported: %s", from); + + checkArgument(from.isOvfDescriptorUploaded(), "ovf descriptor is not uploaded: %s", from); + Envelope ovf = getOVFForVAppTemplateAndValidate(from); + return ovf; + } + + private Envelope getOVFForVAppTemplateAndValidate(VAppTemplate from) throws IllegalArgumentException { + Envelope ovf; + try { + ovf = envelopes.get(from.getHref()); + checkArgument(ovf.getVirtualSystem().getVirtualHardwareSections().size() > 0, + "no hardware sections exist in ovf %s", ovf); + } catch (ExecutionException e) { + throw new IllegalArgumentException("no ovf envelope found for: " + from, e); + } + return ovf; + } +} \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java index 1524eeb4cf..eb5bf45e9a 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java @@ -92,7 +92,24 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter listHardwareProfiles() { - return templates.get(); + return supportedTemplates(); + } + + private Iterable supportedTemplates() { + return Iterables.filter(templates.get(), new Predicate() { + + @Override + public boolean apply(VAppTemplate from) { + try { + templateToEnvelope.apply(from); + } catch (IllegalArgumentException e){ + logger.warn("Unsupported: "+ e.getMessage()); + return false; + } + return true; + } + + }); } @Override @@ -206,4 +223,4 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter locationPredicate = new Predicate() { + final Predicate locationPredicate = new Predicate() { @Override public boolean apply(ComputeMetadata input) { boolean returnVal = true; @@ -314,7 +315,8 @@ public class TemplateBuilderImpl implements TemplateBuilder { if (input.getName() == null) returnVal = false; else - returnVal = input.getName().contains(imageName) || input.getName().matches(imageName); + returnVal = input.getName().equals(imageName) || input.getName().contains(imageName) + || input.getName().matches(imageName); } return returnVal; } @@ -324,6 +326,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { return "imageName(" + imageName + ")"; } }; + private final Predicate imageDescriptionPredicate = new Predicate() { @Override public boolean apply(Image input) { @@ -350,10 +353,6 @@ public class TemplateBuilderImpl implements TemplateBuilder { boolean returnVal = true; if (hardwareId != null) { returnVal = hardwareId.equals(input.getId()); - // match our input params so that the later predicates pass. - if (returnVal) { - fromHardware(input); - } } return returnVal; } @@ -388,9 +387,36 @@ public class TemplateBuilderImpl implements TemplateBuilder { return "minRam(" + minRam + ")"; } }; - private final Predicate hardwarePredicate = and(hardwareIdPredicate, locationPredicate, - hardwareCoresPredicate, hardwareRamPredicate); + private Predicate buildHardwarePredicate() { + List> predicates = newArrayList(); + if (hardwareId != null) { + predicates.add(hardwareIdPredicate); + } else { + if (location != null) + predicates.add(new Predicate() { + + @Override + public boolean apply(Hardware input) { + return locationPredicate.apply(input); + } + + @Override + public String toString() { + return locationPredicate.toString(); + } + }); + predicates.add(hardwareCoresPredicate); + predicates.add(hardwareRamPredicate); + } + + // looks verbose, but explicit type needed for this to compile + // properly + Predicate hardwarePredicate = predicates.size() == 1 ? Iterables.> get(predicates, 0) + : Predicates. and(predicates); + return hardwarePredicate; + } + static final Ordering DEFAULT_SIZE_ORDERING = new Ordering() { public int compare(Hardware left, Hardware right) { return ComparisonChain.start().compare(getCores(left), getCores(right)).compare(left.getRam(), right.getRam()) @@ -407,6 +433,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { return ComparisonChain.start() .compare(left.getName(), right.getName(), Ordering. natural().nullsLast()) .compare(left.getVersion(), right.getVersion(), Ordering. natural().nullsLast()) + .compare(left.getDescription(), right.getDescription(), Ordering. natural().nullsLast()) .compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(),// Ordering. natural().nullsLast()) .compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(),// @@ -543,6 +570,15 @@ public class TemplateBuilderImpl implements TemplateBuilder { }; + + private static final Function hardwareToId = new Function() { + + @Override + public String apply(Hardware arg0) { + return arg0.getId(); + } + + }; /** * {@inheritDoc} */ @@ -554,12 +590,14 @@ public class TemplateBuilderImpl implements TemplateBuilder { defaultTemplate.options(options); return defaultTemplate.build(); } - if (location == null) - location = defaultLocation.get(); + if (options == null) options = optionsProvider.get(); logger.debug(">> searching params(%s)", this); Set images = getImages(); + if (location == null) + location = defaultLocation.get(); + Predicate imagePredicate = buildImagePredicate(); Iterable supportedImages = filter(images, buildImagePredicate()); if (size(supportedImages) == 0) { @@ -570,10 +608,10 @@ public class TemplateBuilderImpl implements TemplateBuilder { images); } } - Hardware hardware = resolveSize(hardwareSorter(), supportedImages); + + Hardware hardware = resolveHardware(hardwareSorter(), supportedImages); Image image = resolveImage(hardware, supportedImages); logger.debug("<< matched image(%s)", image.getId()); - return new TemplateImpl(image, hardware, location, options); } @@ -584,36 +622,50 @@ public class TemplateBuilderImpl implements TemplateBuilder { throw exception; } - protected Hardware resolveSize(Ordering hardwareOrdering, final Iterable images) { + protected Hardware resolveHardware(Ordering hardwareOrdering, final Iterable images) { Set hardwarel = hardwares.get(); + Iterable hardwaresThatAreCompatibleWithOurImages = ImmutableSet.of(); + try { + hardwaresThatAreCompatibleWithOurImages = filter(hardwarel, new Predicate() { + @Override + public boolean apply(final Hardware hardware) { + return Iterables.any(images, new Predicate() { + + @Override + public boolean apply(Image input) { + return hardware.supportsImage().apply(input); + } + + @Override + public String toString() { + return "hardware(" + hardware + ").supportsImage()"; + } + + }); + + } + }); + } catch (NoSuchElementException exception) { + + } + if (size(hardwaresThatAreCompatibleWithOurImages) == 0) { + String message = format("no hardware profiles support images matching params: %s", toString()); + NoSuchElementException exception = new NoSuchElementException(message); + if (logger.isTraceEnabled()) + logger.warn(exception, "hardware profiles %s\nimage ids %s", transform(hardwarel, hardwareToId), transform( + images, imageToId)); + throw exception; + } + Predicate hardwarePredicate = buildHardwarePredicate(); Hardware hardware; try { - Iterable hardwaresThatAreCompatibleWithOurImages = filter(hardwarel, - new Predicate() { - @Override - public boolean apply(final Hardware hardware) { - return Iterables.any(images, new Predicate() { - - @Override - public boolean apply(Image input) { - return hardware.supportsImage().apply(input); - } - - @Override - public String toString() { - return "hardware(" + hardware + ").supportsImage()"; - } - - }); - - } - }); hardware = hardwareOrdering.max(filter(hardwaresThatAreCompatibleWithOurImages, hardwarePredicate)); } catch (NoSuchElementException exception) { - String message = format("no hardware profiles support images matching params: %s", toString()); + String message = format("no hardware profiles match params: %s", hardwarePredicate); exception = new NoSuchElementException(message); if (logger.isTraceEnabled()) - logger.warn(exception, "hardware profiles %s\nimage ids %s", hardwarel, transform(images, imageToId)); + logger.warn(exception, "hardware profiles %s", transform(hardwaresThatAreCompatibleWithOurImages, + hardwareToId)); throw exception; } logger.debug("<< matched hardware(%s)", hardware.getId()); @@ -649,6 +701,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { return "hardware(" + hardware + ").supportsImage()"; } }; + try { Iterable matchingImages = filter(supportedImages, imagePredicate); if (logger.isTraceEnabled()) diff --git a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java index 260e09d493..c979c78489 100644 --- a/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java +++ b/compute/src/test/java/org/jclouds/compute/domain/internal/TemplateBuilderImplTest.java @@ -18,10 +18,10 @@ */ package org.jclouds.compute.domain.internal; +import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; -import static org.easymock.classextension.EasyMock.createMock; -import static org.easymock.classextension.EasyMock.replay; -import static org.easymock.classextension.EasyMock.verify; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; import static org.testng.Assert.assertEquals; import java.util.NoSuchElementException; @@ -49,9 +49,50 @@ import com.google.common.collect.ImmutableSet; * * @author Adrian Cole */ -@Test(groups = "unit") +@Test(groups = "unit", singleThreaded = true) public class TemplateBuilderImplTest { + + @SuppressWarnings("unchecked") + public void testLocationPredicateWhenComputeMetadataIsNotLocationBound() { + Location defaultLocation = createMock(Location.class); + Image image = createMock(Image.class); + OperatingSystem os = createMock(OperatingSystem.class); + Hardware hardware = new HardwareBuilder().id("hardwareId").build(); + + Supplier> locations = Suppliers.> ofInstance(ImmutableSet + . of(defaultLocation)); + Supplier> images = Suppliers.> ofInstance(ImmutableSet. of( + image)); + Supplier> hardwares = Suppliers.> ofInstance(ImmutableSet + . of(hardware)); + Provider optionsProvider = createMock(Provider.class); + Provider templateBuilderProvider = createMock(Provider.class); + TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class); + + expect(image.getLocation()).andReturn(defaultLocation).anyTimes(); + expect(image.getProviderId()).andReturn("imageId").anyTimes(); + expect(defaultLocation.getId()).andReturn("location").anyTimes(); + + replay(image); + replay(os); + replay(defaultTemplate); + replay(defaultLocation); + replay(optionsProvider); + replay(templateBuilderProvider); + + TemplateBuilderImpl template = createTemplateBuilder(null, locations, images, hardwares, defaultLocation, + optionsProvider, templateBuilderProvider); + assert template.locationPredicate.apply(hardware); + + verify(image); + verify(os); + verify(defaultTemplate); + verify(defaultLocation); + verify(optionsProvider); + verify(templateBuilderProvider); + } + @SuppressWarnings("unchecked") @Test public void testResolveImages() { @@ -75,6 +116,8 @@ public class TemplateBuilderImplTest { expect(image.getName()).andReturn("imageName"); expect(image2.getName()).andReturn("imageName"); + expect(image.getDescription()).andReturn("imageDescription"); + expect(image2.getDescription()).andReturn("imageDescription"); expect(image.getVersion()).andReturn("imageVersion"); expect(image2.getVersion()).andReturn("imageVersion"); expect(image.getOperatingSystem()).andReturn(os).atLeastOnce(); @@ -179,7 +222,7 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test - public void testSizeWithImageIdPredicateOnlyAcceptsImage() { + public void testHardwareWithImageIdPredicateOnlyAcceptsImage() { Location defaultLocation = createMock(Location.class); Image image = createMock(Image.class); OperatingSystem os = createMock(OperatingSystem.class); @@ -239,7 +282,56 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test - public void testSizeWithImageIdPredicateOnlyDoesntImage() { + public void testHardwareWithImageIdPredicateOnlyAcceptsImageWhenLocationNull() { + Location defaultLocation = createMock(Location.class); + Image image = createMock(Image.class); + OperatingSystem os = createMock(OperatingSystem.class); + + Hardware hardware = new HardwareBuilder().id("hardwareId").supportsImage(ImagePredicates.idEquals("myregion/imageId")) + .build(); + + Supplier> locations = Suppliers.> ofInstance(ImmutableSet + . of(defaultLocation)); + Supplier> images = Suppliers.> ofInstance(ImmutableSet + . of(image)); + Supplier> hardwares = Suppliers.> ofInstance(ImmutableSet + . of(hardware)); + Provider optionsProvider = createMock(Provider.class); + Provider templateBuilderProvider = createMock(Provider.class); + TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class); + + expect(optionsProvider.get()).andReturn(new TemplateOptions()); + expect(image.getId()).andReturn("myregion/imageId").atLeastOnce(); + expect(image.getLocation()).andReturn(null).atLeastOnce(); + expect(image.getName()).andReturn(null).atLeastOnce(); + expect(image.getDescription()).andReturn(null).atLeastOnce(); + expect(image.getVersion()).andReturn(null).atLeastOnce(); + expect(image.getOperatingSystem()).andReturn(os).atLeastOnce(); + expect(image.getProviderId()).andReturn("imageId").anyTimes(); + + expect(defaultLocation.getId()).andReturn("myregion").anyTimes(); + + expect(os.getName()).andReturn(null).atLeastOnce(); + expect(os.getVersion()).andReturn(null).atLeastOnce(); + expect(os.getFamily()).andReturn(null).atLeastOnce(); + expect(os.getDescription()).andReturn(null).atLeastOnce(); + expect(os.getArch()).andReturn(null).atLeastOnce(); + expect(os.is64Bit()).andReturn(false).atLeastOnce(); + + replay(image, os, defaultTemplate, defaultLocation, optionsProvider, templateBuilderProvider); + + TemplateBuilderImpl template = createTemplateBuilder(null, locations, images, hardwares, defaultLocation, + optionsProvider, templateBuilderProvider); + + template.imageId("myregion/imageId").build(); + + verify(image, os, defaultTemplate, defaultLocation, optionsProvider, templateBuilderProvider); + + } + + @SuppressWarnings("unchecked") + @Test + public void testHardwareWithImageIdPredicateOnlyDoesntImage() { Location defaultLocation = createMock(Location.class); Image image = createMock(Image.class); OperatingSystem os = createMock(OperatingSystem.class); @@ -567,9 +659,8 @@ public class TemplateBuilderImplTest { Provider templateBuilderProvider = createMock(Provider.class); TemplateOptions defaultOptions = createMock(TemplateOptions.class); - expect(defaultLocation.getId()).andReturn("us-east-1"); - expect(optionsProvider.get()).andReturn(defaultOptions); + expect(defaultLocation.getId()).andReturn("us-east-1"); replay(defaultOptions); replay(defaultLocation); @@ -580,11 +671,11 @@ public class TemplateBuilderImplTest { optionsProvider, templateBuilderProvider); try { - template.imageDescriptionMatches("region/ami").build(); + template.imageDescriptionMatches("description").build(); assert false; } catch (NoSuchElementException e) { // make sure big data is not in the exception message - assertEquals(e.getMessage(), "no image matched predicate: And(locationEqualsOrChildOf(us-east-1),imageDescription(region/ami))"); + assertEquals(e.getMessage(), "no image matched predicate: And(locationEqualsOrChildOf(us-east-1),imageDescription(description))"); } verify(defaultOptions); From 87ced325e1aa51b5a972a0041234b91d41ccb657 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 14 Jan 2012 21:13:29 -0800 Subject: [PATCH 64/82] Issue 710: support vCloud Director 1.5 via vCloud 1.0 API --- .../vcloud/TaskInErrorStateException.java | 43 +++ .../vcloud/TaskStillRunningException.java | 43 +++ ...antiateVAppTemplateParamsToXmlPayload.java | 92 +++---- ...CloudComputeServiceDependenciesModule.java | 12 + .../functions/HardwareForVAppTemplate.java | 24 +- .../functions/ImageForVAppTemplate.java | 22 +- ...velopeOrThrowIllegalArgumentException.java | 3 +- ...IntoNameThenCustomizeDeployAndPowerOn.java | 244 +++++++++++++----- .../strategy/VCloudComputeServiceAdapter.java | 94 ++++--- .../compute/util/VCloudComputeUtils.java | 4 - .../vcloud/config/VCloudRestClientModule.java | 59 ++++- .../java/org/jclouds/vcloud/domain/VApp.java | 9 + .../vcloud/domain/internal/TaskImpl.java | 9 +- .../vcloud/domain/internal/VAppImpl.java | 19 +- .../vcloud/domain/network/NetworkConfig.java | 40 ++- .../functions/AllCatalogItemsInOrg.java | 5 - .../DefaultNetworkNameInTemplate.java | 49 ++++ .../vcloud/functions/VAppTemplatesInOrg.java | 30 ++- .../org/jclouds/vcloud/loaders/OVFLoader.java | 49 ++++ .../vcloud/loaders/VAppTemplateLoader.java | 49 ++++ .../InstantiateVAppTemplateOptions.java | 28 +- .../vcloud/predicates/TaskSuccess.java | 3 +- .../org/jclouds/vcloud/xml/VAppHandler.java | 27 +- .../vcloud/xml/VAppTemplateHandler.java | 23 +- .../xml/ovf/VCloudNetworkSectionHandler.java | 4 +- ...ateVAppTemplateParamsToXmlPayloadTest.java | 109 ++++---- .../compute/VCloudComputeServiceLiveTest.java | 55 +--- ...enCustomizeDeployAndPowerOnExpectTest.java | 72 ++++++ .../features/CatalogClientLiveTest.java | 3 +- .../vcloud/features/VmClientLiveTest.java | 2 +- .../internal/BaseVCloudAsyncClientTest.java | 17 ++ .../internal/BaseVCloudClientLiveTest.java | 3 +- .../jclouds/vcloud/xml/VAppHandlerTest.java | 1 + .../vcloud/xml/VAppTemplateHandlerTest.java | 23 +- .../vAppTemplate1.0-vcd15_withNewlines.xml | 109 ++++++++ 35 files changed, 1015 insertions(+), 363 deletions(-) create mode 100644 apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java create mode 100644 apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java create mode 100644 apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java create mode 100644 apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java create mode 100644 apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java create mode 100644 apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java create mode 100644 apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java new file mode 100644 index 0000000000..94908a3c92 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java @@ -0,0 +1,43 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.vcloud; + +import org.jclouds.vcloud.domain.Task; + +/** + * + * @author Adrian Cole + * + */ +public class TaskInErrorStateException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final Task task; + + public TaskInErrorStateException(Task task) { + super("error on task: " + task + " error: " + task.getError()); + this.task = task; + } + + public Task getTask() { + return task; + } + +} diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java new file mode 100644 index 0000000000..c0b47743bc --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java @@ -0,0 +1,43 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.vcloud; + +import org.jclouds.vcloud.domain.Task; + +/** + * + * @author Adrian Cole + * + */ +public class TaskStillRunningException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final Task task; + + public TaskStillRunningException(Task task) { + super("task still running: " + task); + this.task = task; + } + + public Task getTask() { + return task; + } + +} diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java index 9c531a9769..a6aebc28e7 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java @@ -21,7 +21,7 @@ package org.jclouds.vcloud.binders; 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 static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; +import static com.google.common.collect.Iterables.transform; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; @@ -30,8 +30,7 @@ import java.util.Map; import java.util.Properties; import java.util.Set; -import org.jclouds.javax.annotation.Nullable; -import javax.annotation.Resource; +import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import javax.xml.parsers.FactoryConfigurationError; @@ -39,11 +38,10 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jclouds.http.HttpRequest; -import org.jclouds.logging.Logger; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.rest.MapBinder; import org.jclouds.rest.binders.BindToStringPayload; import org.jclouds.rest.internal.GeneratedHttpRequest; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.Vm; @@ -54,10 +52,8 @@ import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; -import com.google.inject.Inject; import com.jamesmurty.utils.XMLBuilder; /** @@ -73,21 +69,21 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder protected final BindToStringPayload stringBinder; protected final ReferenceType defaultNetwork; protected final FenceMode defaultFenceMode; - protected final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate; - protected final VCloudClient client; + protected final LoadingCache templateCache; + protected final Function defaultNetworkNameInTemplate; @Inject - public BindInstantiateVAppTemplateParamsToXmlPayload(DefaultNetworkNameInTemplate defaultNetworkNameInTemplate, - BindToStringPayload stringBinder, @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, - @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema, @Network ReferenceType network, - @Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode, VCloudClient client) { + public BindInstantiateVAppTemplateParamsToXmlPayload(LoadingCache templateCache, + @Network Function defaultNetworkNameInTemplate, BindToStringPayload stringBinder, + @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema, + @Network ReferenceType network, FenceMode fenceMode) { + this.templateCache = templateCache; this.defaultNetworkNameInTemplate = defaultNetworkNameInTemplate; this.ns = ns; this.schema = schema; this.stringBinder = stringBinder; this.defaultNetwork = network; - this.defaultFenceMode = FenceMode.fromValue(fenceMode); - this.client = client; + this.defaultFenceMode = fenceMode; } @Override @@ -97,33 +93,29 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; checkState(gRequest.getArgs() != null, "args should be initialized at this point"); String name = checkNotNull(postParams.remove("name"), "name"); - final URI template = URI.create(checkNotNull(postParams.remove("template"), "template")); - - boolean deploy = true; - boolean powerOn = true; + URI template = URI.create(checkNotNull(postParams.remove("template"), "template")); Set networkConfig = null; - NetworkConfigDecorator networknetworkConfigDecorator = new NetworkConfigDecorator(template, + NetworkConfigDecorator networkConfigDecorator = new NetworkConfigDecorator(templateCache.getUnchecked(template), defaultNetwork.getHref(), defaultFenceMode, defaultNetworkNameInTemplate); InstantiateVAppTemplateOptions options = findOptionsInArgsOrNull(gRequest); if (options != null) { if (options.getNetworkConfig().size() > 0) - networkConfig = Sets.newLinkedHashSet(Iterables.transform(options.getNetworkConfig(), - networknetworkConfigDecorator)); - deploy = ifNullDefaultTo(options.shouldDeploy(), deploy); - powerOn = ifNullDefaultTo(options.shouldPowerOn(), powerOn); + networkConfig = ImmutableSet + .copyOf(transform(options.getNetworkConfig(), networkConfigDecorator)); + } else { + options = new InstantiateVAppTemplateOptions(); } if (networkConfig == null) - networkConfig = ImmutableSet.of(networknetworkConfigDecorator.apply(null)); + networkConfig = ImmutableSet.of(networkConfigDecorator.apply(null)); try { - return stringBinder.bindToRequest( - request, - generateXml(name, options.getDescription(), deploy, powerOn, template, networkConfig)); + return stringBinder.bindToRequest(request, generateXml(name, options.getDescription(), options.shouldDeploy(), + options.shouldPowerOn(), template, networkConfig)); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } catch (FactoryConfigurationError e) { @@ -136,9 +128,9 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder @VisibleForTesting Set ifCustomizationScriptIsSetGetVmsInTemplate(String customizationScript, final URI template) { - Set vms = Sets.newLinkedHashSet(); + Set vms = ImmutableSet.of(); if (customizationScript != null) { - VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template); + VAppTemplate vAppTemplate = templateCache.getUnchecked(template); checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template); vms = vAppTemplate.getChildren(); checkArgument(vms.size() > 0, "no vms found in vAppTemplate %s", vAppTemplate); @@ -147,13 +139,13 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder } protected static final class NetworkConfigDecorator implements Function { - private final URI template; + private final VAppTemplate template; private final URI defaultNetwork; private final FenceMode defaultFenceMode; - private final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate; + private final Function defaultNetworkNameInTemplate; - protected NetworkConfigDecorator(URI template, URI defaultNetwork, FenceMode defaultFenceMode, - DefaultNetworkNameInTemplate defaultNetworkNameInTemplate) { + protected NetworkConfigDecorator(VAppTemplate template, URI defaultNetwork, FenceMode defaultFenceMode, + Function defaultNetworkNameInTemplate) { this.template = checkNotNull(template, "template"); this.defaultNetwork = checkNotNull(defaultNetwork, "defaultNetwork"); this.defaultFenceMode = checkNotNull(defaultFenceMode, "defaultFenceMode"); @@ -166,38 +158,14 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder return new NetworkConfig(defaultNetworkNameInTemplate.apply(template), defaultNetwork, defaultFenceMode); URI network = ifNullDefaultTo(from.getParentNetwork(), defaultNetwork); FenceMode fenceMode = ifNullDefaultTo(from.getFenceMode(), defaultFenceMode); + // using conditional statement instead of ifNullDefaultTo so that we lazy invoke the + // function, as it is an expensive one. String networkName = from.getNetworkName() != null ? from.getNetworkName() : defaultNetworkNameInTemplate - .apply(template); + .apply(template); return new NetworkConfig(networkName, network, fenceMode); } } - @Singleton - public static class DefaultNetworkNameInTemplate implements Function { - @Resource - protected Logger logger = Logger.NULL; - - private final VCloudClient client; - - @Inject - DefaultNetworkNameInTemplate(VCloudClient client) { - this.client = client; - } - - @Override - public String apply(URI template) { - String networkName; - VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template); - checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template); - Set networks = vAppTemplate.getNetworkSection().getNetworks(); - checkArgument(networks.size() > 0, "no networks found in vAppTemplate %s", vAppTemplate); - if (networks.size() > 1) - logger.warn("multiple networks found for %s, choosing first from: %s", vAppTemplate.getName(), networks); - networkName = Iterables.get(networks, 0).getName(); - return networkName; - } - } - protected String generateXml(String name, @Nullable String description, boolean deploy, boolean powerOn, URI template, Iterable networkConfig) throws ParserConfigurationException, FactoryConfigurationError, TransformerException { diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java index 31984337e0..c77c3fb717 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java @@ -45,9 +45,13 @@ import org.jclouds.vcloud.compute.internal.VCloudTemplateBuilderImpl; import org.jclouds.vcloud.compute.options.VCloudTemplateOptions; import org.jclouds.vcloud.compute.strategy.VCloudComputeServiceAdapter; import org.jclouds.vcloud.domain.Org; +import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.VAppTemplate; +import org.jclouds.vcloud.domain.network.FenceMode; +import org.jclouds.vcloud.domain.network.NetworkConfig; +import org.jclouds.vcloud.endpoints.Network; import org.jclouds.vcloud.functions.VAppTemplatesInOrg; import com.google.common.annotations.VisibleForTesting; @@ -110,6 +114,14 @@ public class VCloudComputeServiceDependenciesModule extends AbstractModule { }).to((Class) IdentityFunction.class); } + + @Provides + @Singleton + public NetworkConfig networkConfig(@Network ReferenceType network, FenceMode defaultFenceMode) { + return new NetworkConfig(network.getName(), network.getHref(), defaultFenceMode); + } + + @Singleton public static class DefaultVDC implements Supplier { private final Supplier> locationsSupplier; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java index 0984e0c9da..ac14181132 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java @@ -30,7 +30,6 @@ import org.jclouds.compute.predicates.ImagePredicates; import org.jclouds.logging.Logger; import org.jclouds.ovf.Envelope; import org.jclouds.ovf.VirtualHardwareSection; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.VAppTemplate; import com.google.common.base.Function; @@ -45,37 +44,25 @@ public class HardwareForVAppTemplate implements Function @Resource protected Logger logger = Logger.NULL; - private final VCloudClient client; + private final Function templateToEnvelope; private final FindLocationForResource findLocationForResource; private final VCloudHardwareBuilderFromResourceAllocations rasdToHardwareBuilder; @Inject - protected HardwareForVAppTemplate(VCloudClient client, FindLocationForResource findLocationForResource, + protected HardwareForVAppTemplate(Function templateToEnvelope, + FindLocationForResource findLocationForResource, VCloudHardwareBuilderFromResourceAllocations rasdToHardwareBuilder) { - this.client = checkNotNull(client, "client"); + this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope"); this.findLocationForResource = checkNotNull(findLocationForResource, "findLocationForResource"); this.rasdToHardwareBuilder = checkNotNull(rasdToHardwareBuilder, "rasdToHardwareBuilder"); } - @Override public Hardware apply(VAppTemplate from) { checkNotNull(from, "VAppTemplate"); - if (!from.isOvfDescriptorUploaded()) { - logger.warn("cannot parse hardware as ovf descriptor for %s is not uploaded", from); - return null; - } + Envelope ovf = templateToEnvelope.apply(from); - Envelope ovf = client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(from.getHref()); - if (ovf == null) { - logger.warn("cannot parse hardware as no ovf envelope found for %s", from); - return null; - } - if (ovf.getVirtualSystem().getVirtualHardwareSections().size() == 0) { - logger.warn("cannot parse hardware for %s as no hardware sections exist in ovf %s", ovf); - return null; - } if (ovf.getVirtualSystem().getVirtualHardwareSections().size() > 1) { logger.warn("multiple hardware choices found. using first", ovf); } @@ -89,6 +76,7 @@ public class HardwareForVAppTemplate implements Function builder.ids(from.getHref().toASCIIString()).name(from.getName()).supportsImage( ImagePredicates.idEquals(from.getHref().toASCIIString())); return builder.build(); + } protected String getName(String name) { diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java index 99d1780e52..3bab9811d2 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java @@ -20,14 +20,17 @@ package org.jclouds.vcloud.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; +import javax.annotation.Resource; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.domain.CIMOperatingSystem; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; import org.jclouds.ovf.Envelope; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.VAppTemplate; import com.google.common.base.Function; @@ -37,18 +40,26 @@ import com.google.common.base.Function; */ @Singleton public class ImageForVAppTemplate implements Function { - private final VCloudClient client; + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + public Logger logger = Logger.NULL; + + private final Function templateToEnvelope; private final FindLocationForResource findLocationForResource; @Inject - protected ImageForVAppTemplate(VCloudClient client, FindLocationForResource findLocationForResource) { - this.client = checkNotNull(client, "client"); + protected ImageForVAppTemplate(Function templateToEnvelope, + FindLocationForResource findLocationForResource) { + this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope"); this.findLocationForResource = checkNotNull(findLocationForResource, "findLocationForResource"); } - @Override public Image apply(VAppTemplate from) { + checkNotNull(from, "VAppTemplate"); + Envelope ovf = templateToEnvelope.apply(from); + ImageBuilder builder = new ImageBuilder(); builder.ids(from.getHref().toASCIIString()); builder.uri(from.getHref()); @@ -59,7 +70,6 @@ public class ImageForVAppTemplate implements Function { // otherwise, it could be in a public catalog, which is not assigned to a VDC } builder.description(from.getDescription() != null ? from.getDescription() : from.getName()); - Envelope ovf = client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(from.getHref()); builder.operatingSystem(CIMOperatingSystem.toComputeOs(ovf)); return builder.build(); } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java index b7cebb5964..a72b84ac83 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java @@ -75,4 +75,5 @@ public class ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentExceptio } return ovf; } -} \ No newline at end of file +} + diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java index e98b88dbc1..823bd76aed 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java @@ -18,8 +18,14 @@ */ package org.jclouds.vcloud.compute.strategy; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Predicates.not; +import static com.google.common.collect.Iterables.find; +import static com.google.common.collect.Iterables.get; +import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; import static org.jclouds.compute.util.ComputeServiceUtils.getCores; import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getCredentialsFrom; +import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig; import java.net.URI; @@ -31,7 +37,11 @@ import javax.inject.Singleton; import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.domain.Template; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.logging.Logger; +import org.jclouds.ovf.Network; +import org.jclouds.predicates.validators.DnsNameValidator; +import org.jclouds.vcloud.TaskStillRunningException; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.compute.options.VCloudTemplateOptions; import org.jclouds.vcloud.domain.GuestCustomizationSection; @@ -39,14 +49,16 @@ import org.jclouds.vcloud.domain.NetworkConnection; import org.jclouds.vcloud.domain.NetworkConnectionSection; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; +import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.Vm; import org.jclouds.vcloud.domain.NetworkConnectionSection.Builder; import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; +import org.jclouds.vcloud.domain.network.NetworkConfig; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; -import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; /** * @author Adrian Cole @@ -59,100 +71,218 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA protected final VCloudClient client; protected final Predicate successTester; + protected final LoadingCache vAppTemplates; + protected final NetworkConfig defaultNetworkConfig; + protected final String buildVersion; @Inject - protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(Predicate successTester, - VCloudClient client) { + protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(VCloudClient client, + Predicate successTester, LoadingCache vAppTemplates, + NetworkConfig defaultNetworkConfig, @Named(PROPERTY_BUILD_VERSION) String buildVersion) { this.client = client; this.successTester = successTester; + this.vAppTemplates = vAppTemplates; + this.defaultNetworkConfig = defaultNetworkConfig; + this.buildVersion = buildVersion; } - public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String tag, String name, Template template) { - InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + // TODO: filtering on "none" is a hack until we can filter on + // vAppTemplate.getNetworkConfigSection().getNetworkConfigs() where + // name = getChildren().NetworkConnectionSection.connection where ipallocationmode == none + Predicate networkWithNoIpAllocation = new Predicate() { + + @Override + public boolean apply(Network input) { + return "none".equals(input.getName()); + } + + }; + + /** + * per john ellis at bluelock, vCloud Director 1.5 is more strict than earlier versions. + *

+ * It appears to be 15 characters to match Windows' hostname limitation. Must be alphanumeric, at + * least one non-number character and hyphens and underscores are the only non-alpha character + * allowed. + */ + public static enum ComputerNameValidator { + INSTANCE; + + private DnsNameValidator validator; + + ComputerNameValidator(){ + this.validator = new DnsNameValidator(3, 15); + } + + public void validate(@Nullable String t) throws IllegalArgumentException { + this.validator.validate(t); + } + + } + + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String group, String name, Template template) { + // no sense waiting until failures occur later + ComputerNameValidator.INSTANCE.validate(name); + + URI templateId = URI.create(template.getImage().getId()); + + VAppTemplate vAppTemplate = vAppTemplates.getUnchecked(templateId); + + if (vAppTemplate.getChildren().size() > 1) + throw new UnsupportedOperationException("we currently do not support multiple vms in a vAppTemplate " + + vAppTemplate); + + if (vAppTemplate.getNetworkSection().getNetworks().size() > 1) + throw new UnsupportedOperationException( + "we currently do not support multiple network connections in a vAppTemplate " + vAppTemplate); + + Network networkToConnect = get(vAppTemplate.getNetworkSection().getNetworks(), 0); + + NetworkConfig config; + // if we only have a disconnected network, let's add a new section for the upstream + // TODO: remove the disconnected entry + if (networkWithNoIpAllocation.apply(networkToConnect)) + config = defaultNetworkConfig; + else + config = defaultNetworkConfig.toBuilder().networkName(networkToConnect.getName()).build(); + + // note that in VCD 1.5, the network name after instantiation will be the same as the parent + InstantiateVAppTemplateOptions options = addNetworkConfig(config); // TODO make disk size specifiable // disk((long) ((template.getHardware().getVolumes().get(0).getSize()) * // 1024 * 1024l)); String customizationScript = VCloudTemplateOptions.class.cast(template.getOptions()).getCustomizationScript(); - IpAddressAllocationMode ipAddressAllocationMode = VCloudTemplateOptions.class.cast(template.getOptions()) + IpAddressAllocationMode ipAllocationMode = VCloudTemplateOptions.class.cast(template.getOptions()) .getIpAddressAllocationMode(); - options.description(VCloudTemplateOptions.class.cast(template.getOptions()).getDescription()); + String description = VCloudTemplateOptions.class.cast(template.getOptions()).getDescription(); + if (description == null) + description = vAppTemplate.getName(); + + options.description(description); options.deploy(false); options.powerOn(false); - if (!template.getOptions().shouldBlockUntilRunning()) - options.block(false); - URI VDC = URI.create(template.getLocation().getId()); - URI templateId = URI.create(template.getImage().getId()); logger.debug(">> instantiating vApp vDC(%s) template(%s) name(%s) options(%s) ", VDC, templateId, name, options); VApp vAppResponse = client.getVAppTemplateClient().createVAppInVDCByInstantiatingTemplate(name, VDC, templateId, options); - waitForTask(vAppResponse.getTasks().get(0), vAppResponse); + waitForTask(vAppResponse.getTasks().get(0)); logger.debug("<< instantiated VApp(%s)", vAppResponse.getName()); - // note customization is a serial concern at the moment - Vm vm = Iterables.get(client.getVAppClient().getVApp(vAppResponse.getHref()).getChildren(), 0); - if (customizationScript != null) { - logger.trace(">> updating customization vm(%s) ", vm.getName()); - waitForTask(updateVmWithCustomizationScript(vm, customizationScript), vAppResponse); - logger.trace("<< updated customization vm(%s) ", vm.getName()); - } - if (ipAddressAllocationMode != null) { - logger.trace(">> updating ipAddressAllocationMode(%s) vm(%s) ", ipAddressAllocationMode, vm.getName()); - waitForTask(updateVmWithIpAddressAllocationMode(vm, ipAddressAllocationMode), vAppResponse); - logger.trace("<< updated ipAddressAllocationMode vm(%s) ", vm.getName()); - } + // vm data is available after instantiate completes + vAppResponse = client.getVAppClient().getVApp(vAppResponse.getHref()); + + // per above check, we know there is only a single VM + Vm vm = get(vAppResponse.getChildren(), 0); + + // note we cannot do tasks in parallel or VCD will throw "is busy" errors + + // note we must do this before any other customizations as there is a dependency on + // valid naming conventions before you can perform commands such as updateCPUCount + logger.trace(">> updating customization vm(%s) name->(%s)", vm.getName(), name); + waitForTask(updateVmWithNameAndCustomizationScript(vm, name, customizationScript)); + logger.trace("<< updated customization vm(%s)", name); + + ensureVmHasAllocationModeOrPooled(vAppResponse, ipAllocationMode); + int cpuCount = new Double(getCores(template.getHardware())).intValue(); - logger.trace(">> updating cpuCount(%d) vm(%s) ", cpuCount, vm.getName()); - waitForTask(updateCPUCountOfVm(vm, cpuCount), vAppResponse); - logger.trace("<< updated cpuCount vm(%s) ", vm.getName()); + logger.trace(">> updating cpuCount(%d) vm(%s)", cpuCount, vm.getName()); + waitForTask(updateCPUCountOfVm(vm, cpuCount)); + logger.trace("<< updated cpuCount vm(%s)", vm.getName()); int memoryMB = template.getHardware().getRam(); - logger.trace(">> updating memoryMB(%d) vm(%s) ", memoryMB, vm.getName()); - waitForTask(updateMemoryMBOfVm(vm, memoryMB), vAppResponse); - logger.trace("<< updated memoryMB vm(%s) ", vm.getName()); - logger.trace(">> deploying and powering on vApp(%s) ", vAppResponse.getName()); - vAppResponse = blockOnDeployAndPowerOnIfConfigured(options, vAppResponse, client.getVAppClient() - .deployAndPowerOnVApp(vAppResponse.getHref())); + logger.trace(">> updating memoryMB(%d) vm(%s)", memoryMB, vm.getName()); + waitForTask(updateMemoryMBOfVm(vm, memoryMB)); + logger.trace("<< updated memoryMB vm(%s)", vm.getName()); + logger.trace(">> deploying vApp(%s)", vAppResponse.getName()); + waitForTask(client.getVAppClient().deployVApp(vAppResponse.getHref())); + logger.trace("<< deployed vApp(%s)", vAppResponse.getName()); + + // only after deploy is the password valid + vAppResponse = client.getVAppClient().getVApp(vAppResponse.getHref()); + + logger.trace(">> powering on vApp(%s)", vAppResponse.getName()); + client.getVAppClient().powerOnVApp(vAppResponse.getHref()); + return new NodeAndInitialCredentials(vAppResponse, vAppResponse.getHref().toASCIIString(), getCredentialsFrom(vAppResponse)); } - public void waitForTask(Task task, VApp vAppResponse) { + public void waitForTask(Task task) { if (!successTester.apply(task.getHref())) { - throw new RuntimeException(String.format("failed to %s %s: %s", task.getName(), vAppResponse.getName(), task)); + throw new TaskStillRunningException(task); } } - public Task updateVmWithCustomizationScript(Vm vm, String customizationScript) { + /** + * Naming constraints modifying a VM on a VApp in vCloud Director (at least v1.5) can be more + * strict than those in a vAppTemplate. For example, while it is possible to instantiate a + * vAppTemplate with a VM named (incorrectly) {@code Ubuntu_10.04}, you must change the name to a + * valid (alphanumeric underscore) name before you can update it. + */ + public Task updateVmWithNameAndCustomizationScript(Vm vm, String name, @Nullable String customizationScript) { GuestCustomizationSection guestConfiguration = vm.getGuestCustomizationSection(); - // TODO: determine if the server version is beyond 1.0.0, and if so append - // to, but - // not overwrite the customization script. In version 1.0.0, the api - // returns a script that - // loses newlines. - guestConfiguration.setCustomizationScript(customizationScript); + guestConfiguration.setComputerName(name); + if (customizationScript != null) { + // In version 1.0.0, the api returns a script that loses newlines, so we cannot append to a + // customization script. + // TODO: parameterize whether to overwrite or append existing customization + if (!buildVersion.startsWith("1.0.0") && !"".endsWith(buildVersion) + && guestConfiguration.getCustomizationScript() != null) + customizationScript = guestConfiguration.getCustomizationScript() + "\n" + customizationScript; + + guestConfiguration.setCustomizationScript(customizationScript); + } return client.getVmClient().updateGuestCustomizationOfVm(guestConfiguration, vm.getHref()); } - public Task updateVmWithIpAddressAllocationMode(Vm vm, final IpAddressAllocationMode ipAddressAllocationMode) { + public void ensureVmHasAllocationModeOrPooled(VApp vApp, @Nullable IpAddressAllocationMode ipAllocationMode) { + Network networkToConnect = find(vApp.getNetworkSection().getNetworks(), not(networkWithNoIpAllocation)); + + Vm vm = get(vApp.getChildren(), 0); + NetworkConnectionSection net = vm.getNetworkConnectionSection(); - Builder builder = net.toBuilder(); - builder.connections(Iterables.transform(net.getConnections(), - new Function() { + checkArgument(net.getConnections().size() > 0, "no connections on vm %s", vm); - @Override - public NetworkConnection apply(NetworkConnection arg0) { - return arg0.toBuilder().connected(true).ipAddressAllocationMode(ipAddressAllocationMode).build(); - } + NetworkConnection toConnect = findWithPoolAllocationOrFirst(net); - })); - return client.getVmClient().updateNetworkConnectionOfVm(builder.build(), vm.getHref()); + if (ipAllocationMode == null) + ipAllocationMode = toConnect.getIpAddressAllocationMode(); + + // make sure that we are in fact allocating ips + if (ipAllocationMode == IpAddressAllocationMode.NONE) + ipAllocationMode = IpAddressAllocationMode.POOL; + + if (toConnect.isConnected() && toConnect.getIpAddressAllocationMode() == ipAllocationMode + && toConnect.getNetwork().equals(networkToConnect.getName())) { + // then we don't need to change the network settings, and can save a call + } else { + Builder builder = net.toBuilder(); + builder.connections(ImmutableSet.of(toConnect.toBuilder().network(networkToConnect.getName()).connected(true) + .ipAddressAllocationMode(ipAllocationMode).build())); + logger.trace(">> updating networkConnection vm(%s)", vm.getName()); + + waitForTask(client.getVmClient().updateNetworkConnectionOfVm(builder.build(), vm.getHref())); + logger.trace("<< updated networkConnection vm(%s)", vm.getName()); + + } + + } + + private NetworkConnection findWithPoolAllocationOrFirst(NetworkConnectionSection net) { + return find(net.getConnections(), new Predicate() { + + @Override + public boolean apply(NetworkConnection input) { + return input.getIpAddressAllocationMode() == IpAddressAllocationMode.POOL; + } + + }, get(net.getConnections(), 0)); } public Task updateCPUCountOfVm(Vm vm, int cpuCount) { @@ -162,12 +292,4 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA public Task updateMemoryMBOfVm(Vm vm, int memoryInMB) { return client.getVmClient().updateMemoryMBOfVm(memoryInMB, vm.getHref()); } - - private VApp blockOnDeployAndPowerOnIfConfigured(InstantiateVAppTemplateOptions options, VApp vAppResponse, Task task) { - if (options.shouldBlock()) { - waitForTask(task, vAppResponse); - logger.debug("<< ready vApp(%s)", vAppResponse.getName()); - } - return client.getVAppClient().getVApp(vAppResponse.getHref()); - } } \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java index eb5bf45e9a..5fa129dc4c 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java @@ -35,6 +35,9 @@ import org.jclouds.compute.domain.Template; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; +import org.jclouds.ovf.Envelope; +import org.jclouds.vcloud.TaskInErrorStateException; +import org.jclouds.vcloud.TaskStillRunningException; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudMediaType; import org.jclouds.vcloud.compute.suppliers.OrgAndVDCToLocationSupplier; @@ -47,9 +50,11 @@ import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.suppliers.VAppTemplatesSupplier; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.ImmutableSet.Builder; /** @@ -69,18 +74,20 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter> nameToOrg; protected final Supplier> templates; + protected final Function templateToEnvelope; protected final Supplier> locations; @Inject protected VCloudComputeServiceAdapter(VCloudClient client, Predicate successTester, InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn booter, - Supplier> nameToOrg, VAppTemplatesSupplier templates, - OrgAndVDCToLocationSupplier locations) { + Supplier> nameToOrg, VAppTemplatesSupplier templates, + Function templateToEnvelope, OrgAndVDCToLocationSupplier locations) { this.client = checkNotNull(client, "client"); this.successTester = checkNotNull(successTester, "successTester"); this.booter = checkNotNull(booter, "booter"); this.nameToOrg = checkNotNull(nameToOrg, "nameToOrg"); this.templates = checkNotNull(templates, "templates"); + this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope"); this.locations = checkNotNull(locations, "locations"); } @@ -114,7 +121,7 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter listImages() { - return templates.get(); + return supportedTemplates(); } @Override @@ -157,70 +164,79 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter> deleting vApp(%s)", vApp.getHref()); - waitForTask(client.getVAppClient().deleteVApp(vApp.getHref()), vApp); - logger.debug("<< deleted vApp(%s)", vApp.getHref()); - } - - VApp undeployVAppIfDeployed(VApp vApp) { + VApp vApp = cancelAnyRunningTasks(vappId); if (vApp.getStatus() != Status.OFF) { + logger.debug(">> powering off VApp vApp(%s), current status: %s", vApp.getName(), vApp.getStatus()); + try { + waitForTask(client.getVAppClient().powerOffVApp(vApp.getHref())); + vApp = client.getVAppClient().getVApp(vApp.getHref()); + logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); + } catch (IllegalStateException e) { + logger.warn(e, "<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); + } logger.debug(">> undeploying vApp(%s), current status: %s", vApp.getName(), vApp.getStatus()); try { - waitForTask(client.getVAppClient().undeployVApp(vApp.getHref()), vApp); + waitForTask(client.getVAppClient().undeployVApp(vApp.getHref())); vApp = client.getVAppClient().getVApp(vApp.getHref()); logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); } catch (IllegalStateException e) { logger.warn(e, "<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); } } - return vApp; + logger.debug(">> deleting vApp(%s)", vApp.getHref()); + waitForTask(client.getVAppClient().deleteVApp(vApp.getHref())); + logger.debug("<< deleted vApp(%s)", vApp.getHref()); + } + + VApp waitForPendingTasksToComplete(URI vappId) { + VApp vApp = client.getVAppClient().getVApp(vappId); + if (vApp.getTasks().size() == 0) + return vApp; + for (Task task : vApp.getTasks()) + waitForTask(task); + return client.getVAppClient().getVApp(vappId); + } + + VApp cancelAnyRunningTasks(URI vappId) { + VApp vApp = client.getVAppClient().getVApp(vappId); + if (vApp.getTasks().size() == 0) + return vApp; + for (Task task : vApp.getTasks()) { + try { + client.getTaskClient().cancelTask(task.getHref()); + waitForTask(task); + } catch (TaskInErrorStateException e) { + } + } + return client.getVAppClient().getVApp(vappId); + + } + + public void waitForTask(Task task) { + if (!successTester.apply(task.getHref())) + throw new TaskStillRunningException(task); } @Override public void rebootNode(String in) { URI id = URI.create(checkNotNull(in, "node.id")); - Task task = client.getVAppClient().resetVApp(id); - successTester.apply(task.getHref()); - + waitForTask(client.getVAppClient().resetVApp(id)); } @Override public void resumeNode(String in) { URI id = URI.create(checkNotNull(in, "node.id")); - Task task = client.getVAppClient().powerOnVApp(id); - successTester.apply(task.getHref()); + waitForTask(client.getVAppClient().powerOnVApp(id)); } @Override public void suspendNode(String in) { URI id = URI.create(checkNotNull(in, "node.id")); - Task task = client.getVAppClient().powerOffVApp(id); - successTester.apply(task.getHref()); + waitForTask(client.getVAppClient().powerOffVApp(id)); } } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java index 26d73bca86..93f197db70 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java @@ -77,10 +77,6 @@ public class VCloudComputeUtils { public static LoginCredentials getCredentialsFrom(Vm vm) { LoginCredentials.Builder builder = LoginCredentials.builder(); - builder.user("root"); - if (vm.getOperatingSystemSection() != null && vm.getOperatingSystemSection().getDescription() != null - && vm.getOperatingSystemSection().getDescription().indexOf("Windows") >= 0) - builder.user("Administrator"); if (vm.getGuestCustomizationSection() != null) builder.password(vm.getGuestCustomizationSection().getAdminPassword()); return builder.build(); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java index c54cee2235..e40ed27a47 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java @@ -20,20 +20,24 @@ package org.jclouds.vcloud.config; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.base.Suppliers.compose; import static com.google.common.base.Throwables.propagate; import static com.google.common.collect.Iterables.concat; +import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.getLast; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Maps.transformValues; import static com.google.common.collect.Maps.uniqueIndex; import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED; import java.net.URI; import java.util.Map; -import java.util.Map.Entry; import java.util.SortedMap; +import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -50,6 +54,7 @@ import org.jclouds.http.RequiresHttp; import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.ServerError; +import org.jclouds.ovf.Envelope; import org.jclouds.predicates.RetryablePredicate; import org.jclouds.rest.AsyncClientFactory; import org.jclouds.rest.AuthorizationException; @@ -61,6 +66,7 @@ import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudToken; import org.jclouds.vcloud.VCloudVersionsAsyncClient; import org.jclouds.vcloud.compute.functions.FindLocationForResource; +import org.jclouds.vcloud.compute.functions.ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException; import org.jclouds.vcloud.domain.Catalog; import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.Org; @@ -68,6 +74,8 @@ import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.VCloudSession; import org.jclouds.vcloud.domain.VDC; +import org.jclouds.vcloud.domain.network.FenceMode; +import org.jclouds.vcloud.endpoints.Network; import org.jclouds.vcloud.endpoints.OrgList; import org.jclouds.vcloud.features.CatalogAsyncClient; import org.jclouds.vcloud.features.CatalogClient; @@ -89,22 +97,25 @@ import org.jclouds.vcloud.functions.AllCatalogItemsInCatalog; import org.jclouds.vcloud.functions.AllCatalogItemsInOrg; import org.jclouds.vcloud.functions.AllCatalogsInOrg; import org.jclouds.vcloud.functions.AllVDCsInOrg; +import org.jclouds.vcloud.functions.DefaultNetworkNameInTemplate; import org.jclouds.vcloud.functions.OrgsForLocations; import org.jclouds.vcloud.functions.OrgsForNames; import org.jclouds.vcloud.functions.VAppTemplatesForCatalogItems; import org.jclouds.vcloud.handlers.ParseVCloudErrorFromHttpResponse; import org.jclouds.vcloud.internal.VCloudLoginAsyncClient; +import org.jclouds.vcloud.loaders.OVFLoader; +import org.jclouds.vcloud.loaders.VAppTemplateLoader; import org.jclouds.vcloud.predicates.TaskSuccess; import org.jclouds.vcloud.xml.ovf.VCloudResourceAllocationSettingDataHandler; import com.google.common.base.Function; import com.google.common.base.Predicate; -import static com.google.common.base.Predicates.*; import com.google.common.base.Supplier; -import static com.google.common.base.Suppliers.*; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; -import static com.google.common.collect.Iterables.*; import com.google.inject.Injector; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -192,6 +203,27 @@ public class VCloudRestClientModule extends RestClientModule>>() { }).to(new TypeLiteral() { }); + + bindCacheLoaders(); + + bind(new TypeLiteral>() { + }).annotatedWith(Network.class).to(new TypeLiteral() { + }); + + bind(new TypeLiteral>() { + }).to(new TypeLiteral() { + }); + + } + + protected void bindCacheLoaders() { + bind(new TypeLiteral>() { + }).to(new TypeLiteral() { + }); + + bind(new TypeLiteral>() { + }).to(new TypeLiteral() { + }); } @Provides @@ -486,7 +518,26 @@ public class VCloudRestClientModule extends RestClientModule>>>( authException, seconds, supplier); } + + + @Provides + @Singleton + protected FenceMode defaultFenceMode(@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode){ + return FenceMode.fromValue(fenceMode); + } + + @Provides + @Singleton + protected LoadingCache vAppTemplates(CacheLoader vAppTemplates) { + return CacheBuilder.newBuilder().build(vAppTemplates); + } + @Provides + @Singleton + protected LoadingCache envelopes(CacheLoader envelopes) { + return CacheBuilder.newBuilder().build(envelopes); + } + @Override protected void bindErrorHandlers() { bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseVCloudErrorFromHttpResponse.class); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java index 3efc1a5d86..2ba7ea4d79 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Set; import org.jclouds.javax.annotation.Nullable; +import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; /** * A VApp is the result of instantiation of a {@link VAppTemplate}.

note

@@ -77,4 +78,12 @@ public interface VApp extends ReferenceType { */ Set getChildren(); + /** + * description of the predefined vApp internal networks in this template + * + * @return null if the vApp is not yet instantiated + * @since vcloud api 1.0 + */ + @Nullable + VCloudNetworkSection getNetworkSection(); } \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java index a38dd71f13..828bc29c61 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java @@ -31,6 +31,8 @@ import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.TaskStatus; import org.jclouds.vcloud.domain.VCloudError; +import com.google.common.base.Objects; + /** * * @author Adrian Cole @@ -88,10 +90,9 @@ public class TaskImpl extends ReferenceTypeImpl implements Task { @Override public String toString() { - return "TaskImpl [endTime=" + endTime + ", error=" + error + ", expiryTime=" + expiryTime + ", operation=" - + operation + ", owner=" + owner + ", startTime=" + startTime + ", status=" + status + ", getHref()=" - + getHref() + ", getName()=" + getName() + ", getType()=" + getType() + ", toString()=" - + super.toString() + ", getClass()=" + getClass() + "]"; + return Objects.toStringHelper("").add("href", getHref()).add("name", getName()).add("owner", owner).add( + "operation", operation).add("startTime", startTime).add("endTime", endTime) + .add("expiryTime", expiryTime).add("error", error).toString(); } public Date getExpiryTime() { diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java index f44a7639f6..fc7eb44f8e 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java @@ -31,6 +31,7 @@ import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.Vm; +import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -51,9 +52,12 @@ public class VAppImpl extends ReferenceTypeImpl implements VApp { private final List tasks = Lists.newArrayList(); private final boolean ovfDescriptorUploaded; private final Set children = Sets.newLinkedHashSet(); - + @Nullable + private final VCloudNetworkSection networkSection; + public VAppImpl(String name, String type, URI id, Status status, ReferenceType vdc, @Nullable String description, - Iterable tasks, boolean ovfDescriptorUploaded, Iterable children) { + Iterable tasks, boolean ovfDescriptorUploaded, Iterable children, + @Nullable VCloudNetworkSection networkSection) { super(name, type, id); this.status = checkNotNull(status, "status"); this.vdc = vdc;// TODO: once <1.0 is killed check not null @@ -61,6 +65,7 @@ public class VAppImpl extends ReferenceTypeImpl implements VApp { Iterables.addAll(this.tasks, checkNotNull(tasks, "tasks")); this.ovfDescriptorUploaded = ovfDescriptorUploaded; Iterables.addAll(this.children, checkNotNull(children, "children")); + this.networkSection = networkSection; // can be null when copying } /** @@ -110,7 +115,15 @@ public class VAppImpl extends ReferenceTypeImpl implements VApp { public Set getChildren() { return children; } - + + /** + * {@inheritDoc} + */ + @Override + public VCloudNetworkSection getNetworkSection() { + return networkSection; + } + @Override public int hashCode() { final int prime = 31; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java index c2fb6708c6..3a5ec8b6af 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java @@ -23,12 +23,51 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.net.URI; import org.jclouds.javax.annotation.Nullable; +import org.jclouds.ovf.NetworkSection; /** * * @author Adrian Cole */ public class NetworkConfig { + + public Builder toBuilder() { + return builder().fromNetworkConfig(this); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String networkName; + private URI parentNetwork; + private FenceMode fenceMode; + + public Builder networkName(String networkName) { + this.networkName = networkName; + return this; + } + + public Builder parentNetwork(URI parentNetwork) { + this.parentNetwork = parentNetwork; + return this; + } + + public Builder fenceMode(FenceMode fenceMode) { + this.fenceMode = fenceMode; + return this; + } + + public Builder fromNetworkConfig(NetworkConfig in) { + return networkName(in.getNetworkName()).parentNetwork(in.getParentNetwork()).fenceMode(in.getFenceMode()); + } + + public NetworkConfig build() { + return new NetworkConfig(networkName, parentNetwork, fenceMode); + } + } + @Nullable private final String networkName; private final URI parentNetwork; @@ -87,7 +126,6 @@ public class NetworkConfig { return fenceMode; } - @Override public int hashCode() { final int prime = 31; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java index 115182673c..fc48add5f6 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java @@ -18,11 +18,9 @@ */ package org.jclouds.vcloud.functions; -import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Singleton; -import org.jclouds.logging.Logger; import org.jclouds.vcloud.domain.Catalog; import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.Org; @@ -36,9 +34,6 @@ import com.google.common.collect.Iterables; @Singleton public class AllCatalogItemsInOrg implements Function> { - @Resource - public Logger logger = Logger.NULL; - private final Function> allCatalogsInOrg; private final Function> allCatalogItemsInCatalog; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java new file mode 100644 index 0000000000..4c947e843d --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.vcloud.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.Iterables.get; + +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.ovf.Network; +import org.jclouds.vcloud.domain.VAppTemplate; + +import com.google.common.base.Function; + +@Singleton +public class DefaultNetworkNameInTemplate implements Function { + @Resource + protected Logger logger = Logger.NULL; + + @Override + public String apply(VAppTemplate vAppTemplate) { + checkArgument(vAppTemplate != null, "vAppTemplate was null!"); + Set networks = vAppTemplate.getNetworkSection().getNetworks(); + checkArgument(networks.size() > 0, "no networks found in vAppTemplate %s", vAppTemplate); + if (networks.size() > 1) + logger.warn("multiple networks found for %s, choosing first from: %s", vAppTemplate.getName(), networks); + return get(networks, 0).getName(); + } +} \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java index f2ea52af28..b4b733dc52 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java @@ -18,20 +18,21 @@ */ package org.jclouds.vcloud.functions; -import java.util.Map; +import static com.google.common.base.Predicates.and; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.filter; import javax.inject.Inject; import javax.inject.Singleton; -import org.jclouds.domain.Credentials; import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.Org; +import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.VAppTemplate; -import org.jclouds.vcloud.functions.AllCatalogItemsInOrg; import com.google.common.base.Function; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; /** * @author Adrian Cole @@ -39,13 +40,12 @@ import com.google.common.collect.Iterables; @Singleton public class VAppTemplatesInOrg implements Function> { - private final AllCatalogItemsInOrg allCatalogItemsInOrg; + private final Function> allCatalogItemsInOrg; private final Function, Iterable> vAppTemplatesForCatalogItems; @Inject - VAppTemplatesInOrg(AllCatalogItemsInOrg allCatalogItemsInOrg, - Function, Iterable> vAppTemplatesForCatalogItems, - Map credentialStore) { + VAppTemplatesInOrg(Function> allCatalogItemsInOrg, + Function, Iterable> vAppTemplatesForCatalogItems) { this.allCatalogItemsInOrg = allCatalogItemsInOrg; this.vAppTemplatesForCatalogItems = vAppTemplatesForCatalogItems; } @@ -54,7 +54,17 @@ public class VAppTemplatesInOrg implements Function> public Iterable apply(Org from) { Iterable catalogs = allCatalogItemsInOrg.apply(from); Iterable vAppTemplates = vAppTemplatesForCatalogItems.apply(catalogs); - return Iterables.filter(vAppTemplates, Predicates.notNull()); + return filter(vAppTemplates, and(notNull(), new Predicate(){ + + //TODO: test this + @Override + public boolean apply(VAppTemplate input) { + if (input == null) + return false; + return ImmutableSet.of(Status.RESOLVED, Status.OFF).contains(input.getStatus()); + } + + })); } } \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java new file mode 100644 index 0000000000..719d35da80 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.vcloud.loaders; + +import java.net.URI; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.ovf.Envelope; +import org.jclouds.vcloud.VCloudClient; + +import com.google.common.cache.CacheLoader; + +@Singleton +public class OVFLoader extends CacheLoader { + @Resource + protected Logger logger = Logger.NULL; + + private final VCloudClient client; + + @Inject + OVFLoader(VCloudClient client) { + this.client = client; + } + + @Override + public Envelope load(URI template) { + return client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(template); + } +} \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java new file mode 100644 index 0000000000..3189fafcd2 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.vcloud.loaders; + +import java.net.URI; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.vcloud.VCloudClient; +import org.jclouds.vcloud.domain.VAppTemplate; + +import com.google.common.cache.CacheLoader; + +@Singleton +public class VAppTemplateLoader extends CacheLoader { + @Resource + protected Logger logger = Logger.NULL; + + private final VCloudClient client; + + @Inject + VAppTemplateLoader(VCloudClient client) { + this.client = client; + } + + @Override + public VAppTemplate load(URI template) { + return client.getVAppTemplateClient().getVAppTemplate(template); + } +} \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java index 6212e5ddc7..de7f985fc2 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java @@ -36,18 +36,13 @@ public class InstantiateVAppTemplateOptions { private Boolean customizeOnInstantiate; private String description = null; - private boolean block = true; private boolean deploy = true; private boolean powerOn = true; public String getDescription() { return description; } - - public boolean shouldBlock() { - return block; - } - + public boolean shouldDeploy() { return deploy; } @@ -80,14 +75,6 @@ public class InstantiateVAppTemplateOptions { this.powerOn = powerOn; return this; } - - /** - * block until instantiate or deployment operations complete? - */ - public InstantiateVAppTemplateOptions block(boolean block) { - this.block = block; - return this; - } /** * {@networkConfig VAppTemplate}s have internal networks that can be @@ -116,14 +103,6 @@ public class InstantiateVAppTemplateOptions { public static class Builder { - /** - * @see InstantiateVAppTemplateOptions#block - */ - public static InstantiateVAppTemplateOptions block(boolean block) { - InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); - return options.block(block); - } - /** * @see InstantiateVAppTemplateOptions#description */ @@ -161,14 +140,13 @@ public class InstantiateVAppTemplateOptions { @Override public String toString() { return "[networkConfig=" + networkConfig + ", customizeOnInstantiate=" + customizeOnInstantiate - + ", description=" + description + ", block=" + block + ", deploy=" + deploy + ", powerOn=" + powerOn + "]"; + + ", description=" + description + ", deploy=" + deploy + ", powerOn=" + powerOn + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + (block ? 1231 : 1237); result = prime * result + ((customizeOnInstantiate == null) ? 0 : customizeOnInstantiate.hashCode()); result = prime * result + (deploy ? 1231 : 1237); result = prime * result + ((description == null) ? 0 : description.hashCode()); @@ -186,8 +164,6 @@ public class InstantiateVAppTemplateOptions { if (getClass() != obj.getClass()) return false; InstantiateVAppTemplateOptions other = (InstantiateVAppTemplateOptions) obj; - if (block != other.block) - return false; if (customizeOnInstantiate == null) { if (other.customizeOnInstantiate != null) return false; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java index 04256295fd..00f3346a2b 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java @@ -24,6 +24,7 @@ import javax.annotation.Resource; import javax.inject.Singleton; import org.jclouds.logging.Logger; +import org.jclouds.vcloud.TaskInErrorStateException; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.TaskStatus; @@ -59,7 +60,7 @@ public class TaskSuccess implements Predicate { return false; logger.trace("%s: looking for status %s: currently: %s", task, TaskStatus.SUCCESS, task.getStatus()); if (task.getStatus() == TaskStatus.ERROR) - throw new RuntimeException("error on task: " + task.getHref() + " error: " + task.getError()); + throw new TaskInErrorStateException(task); return task.getStatus() == TaskStatus.SUCCESS; } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java index 5cfeb16997..a39e2d4c44 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java @@ -35,6 +35,8 @@ import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.Vm; import org.jclouds.vcloud.domain.internal.VAppImpl; +import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; +import org.jclouds.vcloud.xml.ovf.VCloudNetworkSectionHandler; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -48,11 +50,14 @@ public class VAppHandler extends ParseSax.HandlerWithResult { protected final TaskHandler taskHandler; protected final VmHandler vmHandler; + protected final VCloudNetworkSectionHandler networkSectionHandler; @Inject - public VAppHandler(TaskHandler taskHandler, VmHandler vmHandler) { + public VAppHandler(TaskHandler taskHandler, VmHandler vmHandler, + VCloudNetworkSectionHandler networkSectionHandler) { this.taskHandler = taskHandler; this.vmHandler = vmHandler; + this.networkSectionHandler = networkSectionHandler; } protected StringBuilder currentText = new StringBuilder(); @@ -66,11 +71,13 @@ public class VAppHandler extends ParseSax.HandlerWithResult { private boolean inChildren; private boolean inTasks; + private boolean inNetworkSection; protected Set children = Sets.newLinkedHashSet(); + private VCloudNetworkSection networkSection; public VApp getResult() { return new VAppImpl(template.getName(), template.getType(), template.getHref(), status, vdc, description, tasks, - ovfDescriptorUploaded, children); + ovfDescriptorUploaded, children, networkSection); } protected int depth = 0; @@ -84,12 +91,16 @@ public class VAppHandler extends ParseSax.HandlerWithResult { inChildren = true; } else if (equalsOrSuffix(qName, "Tasks")) { inTasks = true; + } else if (equalsOrSuffix(qName, "NetworkSection")) { + inNetworkSection = true; } } if (inChildren) { vmHandler.startElement(uri, localName, qName, attrs); } else if (inTasks) { taskHandler.startElement(uri, localName, qName, attrs); + } else if (inNetworkSection) { + networkSectionHandler.startElement(uri, localName, qName, attrs); } else if (equalsOrSuffix(qName, "VApp")) { template = newReferenceType(attributes); if (attributes.containsKey("status")) @@ -111,12 +122,17 @@ public class VAppHandler extends ParseSax.HandlerWithResult { this.tasks.add(taskHandler.getResult()); } else if (equalsOrSuffix(qName, "Description")) { description = SaxUtils.currentOrNull(currentText); + } else if (equalsOrSuffix(qName, "NetworkSection")) { + inNetworkSection = false; + this.networkSection = networkSectionHandler.getResult(); } } if (inChildren) { vmHandler.endElement(uri, name, qName); } else if (inTasks) { taskHandler.endElement(uri, name, qName); + } else if (inNetworkSection) { + networkSectionHandler.endElement(uri, name, qName); } else if (equalsOrSuffix(qName, "ovfDescriptorUploaded")) { ovfDescriptorUploaded = Boolean.parseBoolean(SaxUtils.currentOrNull(currentText)); } @@ -124,11 +140,14 @@ public class VAppHandler extends ParseSax.HandlerWithResult { } public void characters(char ch[], int start, int length) { - currentText.append(ch, start, length); if (inTasks) taskHandler.characters(ch, start, length); - if (inChildren) + else if (inChildren) vmHandler.characters(ch, start, length); + else if (inNetworkSection) + networkSectionHandler.characters(ch, start, length); + else + currentText.append(ch, start, length); } } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java index 8a49e1447b..43d66a814b 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java @@ -18,6 +18,7 @@ */ package org.jclouds.vcloud.xml; +import static org.jclouds.util.SaxUtils.equalsOrSuffix; import static org.jclouds.vcloud.util.Utils.newReferenceType; import java.util.List; @@ -83,11 +84,11 @@ public class VAppTemplateHandler extends ParseSax.HandlerWithResult attributes = SaxUtils.cleanseAttributes(attrs); - if (qName.endsWith("Children")) { + if (equalsOrSuffix(qName, "Children")) { inChildren = true; - } else if (qName.endsWith("Tasks")) { + } else if (equalsOrSuffix(qName, "Tasks")) { inTasks = true; - } else if (qName.endsWith("NetworkSection")) { + } else if (equalsOrSuffix(qName, "NetworkSection")) { inNetworkSection = true; } if (inChildren) { @@ -96,26 +97,26 @@ public class VAppTemplateHandler extends ParseSax.HandlerWithResult attributes = SaxUtils.cleanseAttributes(attrs); - if (qName.endsWith("NetworkSection")) { + if (equalsOrSuffix(qName, "NetworkSection")) { this.net = Utils.newReferenceType(attributes); } networkSectionHandler.startElement(uri, localName, qName, attrs); diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java index 0aa1667708..d77d684bd3 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java @@ -24,31 +24,35 @@ import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig; +import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; import java.io.IOException; import java.net.URI; import java.util.Map; import java.util.Properties; +import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.util.Strings2; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudPropertiesBuilder; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl; import org.jclouds.vcloud.domain.network.FenceMode; import org.jclouds.vcloud.domain.network.NetworkConfig; -import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; import org.jclouds.vcloud.endpoints.Network; -import org.jclouds.vcloud.features.VAppTemplateClient; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import org.testng.annotations.Test; +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.inject.AbstractModule; import com.google.inject.Guice; @@ -63,22 +67,37 @@ import com.google.inject.name.Names; */ @Test(groups = "unit") public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { - Injector createInjector(URI vAppTemplate, VAppTemplate value) { - final VCloudClient client = createMock(VCloudClient.class); - final VAppTemplateClient tclient = createMock(VAppTemplateClient.class); - - expect(client.getVAppTemplateClient()).andReturn(tclient).anyTimes(); - expect(tclient.getVAppTemplate(vAppTemplate)).andReturn(value).anyTimes(); - replay(client); - replay(tclient); + Injector createInjector(final URI vAppTemplate, final VAppTemplate value) { return Guice.createInjector(new AbstractModule() { + @SuppressWarnings("unused") + @Provides + @Singleton + @Network + protected Function templateToDefaultNetworkName() { + return Functions.forMap(ImmutableMap.of(value, "vAppNet-vApp Internal")); + } + + @SuppressWarnings("unused") + @Provides + @Singleton + protected LoadingCache templateIdToVAppTemplate() { + return CacheBuilder.newBuilder().build( + CacheLoader.from(Functions.forMap(ImmutableMap.of(vAppTemplate, value)))); + } + @Override protected void configure() { Properties props = new Properties(); Names.bindProperties(binder(), checkNotNull(new VCloudPropertiesBuilder(props).build(), "properties")); - bind(VCloudClient.class).toInstance(client); + } + + @SuppressWarnings("unused") + @Provides + @Singleton + public FenceMode defaultFenceMode(@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode) { + return FenceMode.fromValue(fenceMode); } @SuppressWarnings("unused") @@ -86,7 +105,8 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { @Provides @Singleton ReferenceType provideNetwork() { - return new ReferenceTypeImpl(null, null, URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1990")); + return new ReferenceTypeImpl(null, null, URI + .create("https://vcenterprise.bluelock.com/api/v1.0/network/1990")); } }); } @@ -94,91 +114,72 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { public void testDefault() throws IOException { URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); VAppTemplate template = createMock(VAppTemplate.class); - VCloudNetworkSection net = createMock(VCloudNetworkSection.class); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml")); GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn(ImmutableList. of(new InstantiateVAppTemplateOptions())) - .atLeastOnce(); + .atLeastOnce(); request.setPayload(expected); - expect(template.getNetworkSection()).andReturn(net).atLeastOnce(); - expect(net.getNetworks()).andReturn( - ImmutableSet. of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null))); - - replay(request); - replay(template); - replay(net); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); map.put("template", templateUri.toASCIIString()); binder.bindToRequest(request, map); - verify(request); - verify(template); - verify(net); - + verify(request, template); } public void testDescription() throws IOException { URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); VAppTemplate template = createMock(VAppTemplate.class); - VCloudNetworkSection net = createMock(VCloudNetworkSection.class); - String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-description.xml")); + String expected = Strings2.toStringAndClose(getClass() + .getResourceAsStream("/instantiationparams-description.xml")); GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn( - ImmutableList. of(new InstantiateVAppTemplateOptions().description("my foo"))).atLeastOnce(); + ImmutableList. of(new InstantiateVAppTemplateOptions().description("my foo"))).atLeastOnce(); request.setPayload(expected); - expect(template.getNetworkSection()).andReturn(net).atLeastOnce(); - expect(net.getNetworks()).andReturn( - ImmutableSet. of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null))); - - replay(request); - replay(template); - replay(net); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); map.put("template", templateUri.toASCIIString()); binder.bindToRequest(request, map); - verify(request); - verify(template); - verify(net); + verify(request, template); } - @Test(expectedExceptions = IllegalArgumentException.class) public void testWhenTemplateDoesntExist() throws IOException { URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); - VAppTemplate template = null; + VAppTemplate template = createMock(VAppTemplate.class); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml")); GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn(ImmutableList. of()).atLeastOnce(); request.setPayload(expected); - replay(request); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); map.put("template", templateUri.toASCIIString()); binder.bindToRequest(request, map); - verify(request); + verify(request, template); } @@ -198,7 +199,7 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { replay(request); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); @@ -211,10 +212,10 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { public void testWithNetworkNameFenceMode() throws IOException { URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); - VAppTemplate template = null; + VAppTemplate template = createMock(VAppTemplate.class); - InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha", - URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED)); + InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha", URI + .create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED)); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-network.xml")); @@ -222,16 +223,16 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn(ImmutableList. of(options)).atLeastOnce(); request.setPayload(expected); - replay(request); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); binder.bindToRequest(request, map); - verify(request); + verify(request, template); } } diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java index 2d5ec8acfb..aa6185c6c5 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java @@ -18,22 +18,12 @@ */ package org.jclouds.vcloud.compute; -import static org.testng.Assert.assertEquals; - import org.jclouds.compute.BaseComputeServiceLiveTest; -import org.jclouds.compute.ComputeServiceContextFactory; -import org.jclouds.compute.domain.ComputeMetadata; -import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.rest.RestContext; import org.jclouds.sshj.config.SshjSshClientModule; -import org.jclouds.vcloud.VCloudAsyncClient; -import org.jclouds.vcloud.VCloudClient; -import org.jclouds.vcloud.domain.VApp; import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.inject.Module; /** @@ -46,47 +36,30 @@ public class VCloudComputeServiceLiveTest extends BaseComputeServiceLiveTest { public VCloudComputeServiceLiveTest() { provider = "vcloud"; - // vcloud requires instantiate before deploy, which takes longer than 30 seconds - nonBlockDurationSeconds = 300; + } + + @Override + public void setServiceDefaults() { + // extremely short names needed so that we don't get errors relating to + // guestCustomization.computerName being too long + group = "vcd"; + } + + @Override + public void testOptionToNotBlock() { + // start call has to block until deploy } @Override protected Module getSshModule() { return new SshjSshClientModule(); } - + // vcloud does not support metadata @Override protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap userMetadata) { assert node.getUserMetadata().equals(ImmutableMap. of()) : String.format( - "node userMetadata did not match %s %s", userMetadata, node); - } - - @Override - public void testListNodes() throws Exception { - for (ComputeMetadata node : client.listNodes()) { - assert node.getProviderId() != null; - assert node.getLocation() != null; - assertEquals(node.getType(), ComputeType.NODE); - NodeMetadata allData = client.getNodeMetadata(node.getId()); - System.out.println(allData.getHardware()); - RestContext tmContext = new ComputeServiceContextFactory( - setupRestProperties()).createContext(provider, identity, credential, ImmutableSet. of(), - setupProperties()).getProviderSpecificContext(); - VApp vApp = tmContext.getApi().getVAppClient().findVAppInOrgVDCNamed(null, null, allData.getName()); - assertEquals(vApp.getName(), allData.getName()); - } + "node userMetadata did not match %s %s", userMetadata, node); } - @Test(enabled = true, dependsOnMethods = "testSuspendResume") - @Override - public void testGetNodesWithDetails() throws Exception { - super.testGetNodesWithDetails(); - } - - @Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" }) - @Override - public void testDestroyNodes() { - super.testDestroyNodes(); - } } \ No newline at end of file diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java new file mode 100644 index 0000000000..7cd597f4a6 --- /dev/null +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java @@ -0,0 +1,72 @@ +/** + * 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.vcloud.compute.strategy; + +import static org.testng.Assert.assertEquals; + +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.vcloud.compute.BaseVCloudComputeServiceExpectTest; +import org.jclouds.vcloud.domain.VApp; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +/** + * + * @author Adrian Cole + */ +@Test(singleThreaded = true, testName = "InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest") +public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest extends + BaseVCloudComputeServiceExpectTest { + + // TODO: finish me + @Test(enabled = false) + public void testCreateNodeUsingVCloud1_0ApiAgainstVCloudDirector1_5WhenVAppTemplateHasNetworkNamedNone() + throws Exception { + ComputeService compute = requestsSendResponses(ImmutableMap. builder().put( + versionsRequest, versionsResponseFromVCD1_5).put(version1_0LoginRequest, + successfulVersion1_0LoginResponseFromVCD1_5WithSingleOrg).put(version1_0GetOrgRequest, + successfulVersion1_0GetOrgResponseFromVCD1_5WithSingleTasksListVDCAndNetwork).put( + version1_0GetCatalogRequest, successfulVersion1_0GetCatalogResponseFromVCD1_5WithSingleTemplate).put( + version1_0GetCatalogItemRequest, successfulVersion1_0GetCatalogItemResponseFromVCD1_5ForTemplate).put( + version1_0GetVDCRequest, successfulVersion1_0GetVDCResponseFromVCD1_5WithSingleTemplateAndNetwork).put( + version1_0GetVAppTemplateRequest, + successfulVersion1_0GetVAppTemplateResponseFromVCD1_5WithSingleVMAndVDCParent).put( + version1_0GetOVFForVAppTemplateRequest, + successfulVersion1_0GetOVFForVAppTemplateResponseFromVCD1_5WithSingleVM).build()); + + InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn starter = compute.getContext() + .utils().injector().getInstance( + InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.class); + + String group = "group"; + String name = "group-abcd"; + + NodeAndInitialCredentials appAndCreds = starter.createNodeWithGroupEncodedIntoName(group, name, compute + .templateBuilder().build()); + + assertEquals(appAndCreds.getNode().getName(), name); + assertEquals(appAndCreds.getCredentials(), LoginCredentials.builder().user("root").password("fromVApp").build()); + + } +} diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java index 5fc3edda7e..b9ea2a4eb8 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java @@ -43,6 +43,7 @@ public class CatalogClientLiveTest extends BaseVCloudClientLiveTest { @Test public void testFindCatalogIsWriteable() throws Exception { - assertEquals(getVCloudApi().getCatalogClient().findCatalogInOrgNamed(null, null).isReadOnly(), false); + // default catalog should be the public one, unless we are in vCloud 1.0.0 where public catalogs don't work + assertEquals(getVCloudApi().getCatalogClient().findCatalogInOrgNamed(null, null).isReadOnly(), buildVersion.startsWith("1.5")); } } \ No newline at end of file diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java index d1014fe7ae..eee3b7ecb8 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java @@ -98,7 +98,7 @@ public class VmClientLiveTest extends BaseVCloudClientLiveTest { public void testExtendedOptionsWithCustomizationScript() throws Exception { String PARSE_VMTOOLSD = "vmtoolsd --cmd=\"info-get guestinfo.ovfenv\" |grep vCloud_CustomizationInfo|sed 's/.*value=\"\\(.*\\)\".*/\\1/g'"; - String group = prefix + "customize"; + String group = prefix + "cus"; NodeMetadata node = null; try { diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java index db0ce26cc8..84f2ad01c0 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java @@ -32,6 +32,8 @@ import javax.inject.Singleton; import org.jclouds.http.HttpRequest; import org.jclouds.http.RequiresHttp; +import org.jclouds.ovf.Envelope; +import org.jclouds.ovf.xml.EnvelopeHandlerTest; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.RestClientTest; @@ -44,6 +46,7 @@ import org.jclouds.vcloud.domain.AllocationModel; import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.Task; +import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.VCloudSession; import org.jclouds.vcloud.domain.VDC; import org.jclouds.vcloud.domain.VDCStatus; @@ -53,15 +56,19 @@ import org.jclouds.vcloud.domain.internal.OrgImpl; import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl; import org.jclouds.vcloud.domain.internal.VDCImpl; import org.jclouds.vcloud.filters.SetVCloudTokenCookie; +import org.jclouds.vcloud.xml.VAppTemplateHandlerTest; import org.testng.annotations.Test; +import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; +import com.google.common.cache.CacheLoader; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.inject.AbstractModule; import com.google.inject.Module; +import com.google.inject.TypeLiteral; /** * Tests behavior of {@code VCloudAsyncClient} @@ -182,6 +189,16 @@ public abstract class BaseVCloudAsyncClientTest extends RestClientTest { bind(OrgCatalogSupplier.class).to(TestOrgCatalogSupplier.class); bind(OrgCatalogItemSupplier.class).to(TestOrgCatalogItemSupplier.class); } + + @SuppressWarnings("unchecked") + @Override + protected void bindCacheLoaders() { + bind(new TypeLiteral>() { + }).toInstance((CacheLoader) CacheLoader.from(Functions.constant(VAppTemplateHandlerTest.parseTemplate()))); + + bind(new TypeLiteral>() { + }).toInstance((CacheLoader) CacheLoader.from(Functions.constant(EnvelopeHandlerTest.parseEnvelope()))); + } @Override protected Supplier>> provideOrgVDCSupplierCache( diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java index 4ba2dbe5cd..8b3b86b884 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java @@ -42,7 +42,8 @@ import com.google.inject.Module; */ @Test(groups = "live", enabled = true, singleThreaded = true) public abstract class BaseVCloudClientLiveTest extends BaseVersionedServiceLiveTest { - protected String prefix = System.getProperty("user.name"); + // username is too long for name constraints + protected String prefix = "vcd"; protected ComputeService client; diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java index 30292b73a7..d953600aec 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java @@ -71,6 +71,7 @@ public class VAppHandlerTest { .create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1014839439"))); assertEquals(result.getTasks(), ImmutableList.of()); assert result.isOvfDescriptorUploaded(); + assert result.getNetworkSection() != null; Vm vm = Iterables.getOnlyElement(result.getChildren()); VmHandlerTest.checkVm(vm); } diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java index 024ea9ee4b..9bfe3b80e5 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java @@ -54,10 +54,7 @@ import com.google.inject.Injector; public class VAppTemplateHandlerTest { public void testUbuntuTemplate() { - InputStream is = getClass().getResourceAsStream("/vAppTemplate.xml"); - Injector injector = Guice.createInjector(new SaxParserModule()); - Factory factory = injector.getInstance(ParseSax.Factory.class); - VAppTemplate result = factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is); + VAppTemplate result = parseTemplate(); assertEquals(result.getName(), "Ubuntu Template"); assertEquals(result.getHref(), URI .create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/vappTemplate-1201908921")); @@ -118,6 +115,14 @@ public class VAppTemplateHandlerTest { } + public static VAppTemplate parseTemplate() { + InputStream is = VAppTemplateHandlerTest.class.getResourceAsStream("/vAppTemplate.xml"); + Injector injector = Guice.createInjector(new SaxParserModule()); + Factory factory = injector.getInstance(ParseSax.Factory.class); + VAppTemplate result = factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is); + return result; + } + public void testCopyingTemplate() { InputStream is = getClass().getResourceAsStream("/vAppTemplate-copying.xml"); Injector injector = Guice.createInjector(new SaxParserModule()); @@ -148,4 +153,14 @@ public class VAppTemplateHandlerTest { assertEquals(result.getNetworkSection(), null); } + + public void testVAppTemplateWithNewlinesAndNamespacedElements() { + InputStream is = getClass().getResourceAsStream("/vAppTemplate1.0-vcd15_withNewlines.xml"); + Injector injector = Guice.createInjector(new SaxParserModule()); + Factory factory = injector.getInstance(ParseSax.Factory.class); + + factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is); + } + + } diff --git a/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml b/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml new file mode 100644 index 0000000000..9f41d81442 --- /dev/null +++ b/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml @@ -0,0 +1,109 @@ + + + + + + + + Windows 2008 R2 Standard Edition +Service Pack 1 +Internet Explorer 9 + + + + Windows 2008 R2 Standard Edition +Service Pack 1 +Internet Explorer 9 + + Specifies the available VM network connections + 0 + + 0 + 212.54.128.56 + true + 00:50:56:01:0d:3c + POOL + + + + Specifies Guest OS Customization Settings + true + true + false + false + true + true + $6fEPL93 + false + Win2008r2Stand + + ac2ce03d-0491-46f7-afc6-37ffe5b30f74 + + + + The list of logical networks + + + + + + The configuration parameters for logical networks + + + + + true + 212.54.128.1 + 255.255.255.0 + 109.233.48.141 + 109.233.48.142 + + + 212.54.128.4 + 212.54.128.220 + + + + bridged + + + false + 3600 + 7200 + + 212.54.128.201 + 212.54.128.254 + + + + true + + + true + ipTranslation + allowTraffic + + + automatic + ac2ce03d-0491-46f7-afc6-37ffe5b30f74 + 0 + + + + + + false + + + + Lease settings section + + 0 + + + VApp template customization section + true + + \ No newline at end of file From 0b40a3b280aee3ef5b637aa317e08dc565651450 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 01:26:40 -0800 Subject: [PATCH 65/82] hostname is the same as vm name in vCloud --- .../org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java | 1 + 1 file changed, 1 insertion(+) diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java index 58fe90844c..8563585bb2 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java @@ -72,6 +72,7 @@ public class VAppToNodeMetadata implements Function { builder.ids(from.getHref().toASCIIString()); builder.uri(from.getHref()); builder.name(from.getName()); + builder.hostname(from.getName()); builder.location(findLocationForResourceInVDC.apply(from.getVDC())); builder.group(parseGroupFromName(from.getName())); builder.operatingSystem(toComputeOs(from, null)); From 82673e0dd5bed3ad5ecd0a544b1f40297b5862cf Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 02:04:10 -0800 Subject: [PATCH 66/82] Issue 710: update existing vcloud providers --- core/src/main/resources/rest.properties | 4 +- ...ockVCloudZone01ComputeServiceLiveTest.java | 5 -- .../greenhousedata-element-vcloud/pom.xml | 4 ++ ...taElementVCloudComputeServiceLiveTest.java | 17 +----- ...ouseDataElementVCloudVmClientLiveTest.java | 11 ---- providers/stratogen-vcloud-mycloud/pom.xml | 6 ++- ...ratoGenVCloudMyCloudPropertiesBuilder.java | 2 + ...oudMyCloudComputeServiceContextModule.java | 7 +++ ...enVCloudMyCloudComputeServiceLiveTest.java | 36 ------------- ...nVCloudMyCloudTemplateBuilderLiveTest.java | 16 ++++-- sandbox-providers/dunkel-vcd/pom.xml | 37 +++++++++---- ...DunkelVCloudDirectorPropertiesBuilder.java | 2 + .../DunkelVCloudDirectorRestClientModule.java | 8 --- ...loudTokenCookieAndAuthorizationHeader.java | 53 ------------------- ...lVCloudDirectorComputeServiceLiveTest.java | 5 -- .../pom.xml | 48 +++++++++++------ ...irtacorePublicCloudLAXContextBuilder.java} | 14 ++--- ...acorePublicCloudLAXPropertiesBuilder.java} | 14 +++-- ...tacorePublicCloudLAXProviderMetadata.java} | 16 +++--- ...cCloudLAXComputeServiceContextModule.java} | 15 ++++-- ...tacorePublicCloudLAXRestClientModule.java} | 7 +-- .../org.jclouds.providers.ProviderMetadata | 1 + .../VirtacorePublicCloudLAXProviderTest.java} | 12 ++--- ...PublicCloudLAXComputeServiceLiveTest.java} | 13 ++--- ...ublicCloudLAXTemplateBuilderLiveTest.java} | 34 ++++++------ .../src/test/resources/log4j.xml | 0 ...loudTokenCookieAndAuthorizationHeader.java | 53 ------------------- .../org.jclouds.providers.ProviderMetadata | 1 - 28 files changed, 165 insertions(+), 276 deletions(-) delete mode 100644 sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/filters/SetVCloudTokenCookieAndAuthorizationHeader.java rename sandbox-providers/{virtacore-vcloudexpress => virtacore-publiccloud-lax}/pom.xml (55%) rename sandbox-providers/{virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressContextBuilder.java => virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXContextBuilder.java} (68%) rename sandbox-providers/{virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressPropertiesBuilder.java => virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXPropertiesBuilder.java} (67%) rename sandbox-providers/{virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderMetadata.java => virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderMetadata.java} (82%) rename sandbox-providers/{virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressComputeServiceContextModule.java => virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXComputeServiceContextModule.java} (73%) rename sandbox-providers/{virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressRestClientModule.java => virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXRestClientModule.java} (74%) create mode 100644 sandbox-providers/virtacore-publiccloud-lax/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata rename sandbox-providers/{virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderTest.java => virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderTest.java} (69%) rename sandbox-providers/{virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java => virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXComputeServiceLiveTest.java} (74%) rename sandbox-providers/{virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressTemplateBuilderLiveTest.java => virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXTemplateBuilderLiveTest.java} (69%) rename sandbox-providers/{virtacore-vcloudexpress => virtacore-publiccloud-lax}/src/test/resources/log4j.xml (100%) delete mode 100644 sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/filters/SetVCloudTokenCookieAndAuthorizationHeader.java delete mode 100644 sandbox-providers/virtacore-vcloudexpress/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata diff --git a/core/src/main/resources/rest.properties b/core/src/main/resources/rest.properties index 9120345508..892fead643 100644 --- a/core/src/main/resources/rest.properties +++ b/core/src/main/resources/rest.properties @@ -141,8 +141,8 @@ cloudsigma-lvs.contextbuilder=org.jclouds.cloudsigma.CloudSigmaContextBuilder ibm-smartcloud.propertiesbuilder=org.jclouds.ibm.smartcloud.IBMSmartCloudPropertiesBuilder ibm-smartcloud.contextbuilder=org.jclouds.ibm.smartcloud.IBMSmartCloudContextBuilder -virtacore-vcloudexpress.propertiesbuilder=org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressPropertiesBuilder -virtacore-vcloudexpress.contextbuilder=org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressContextBuilder +virtacore-publiccloud-lax.propertiesbuilder=org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXPropertiesBuilder +virtacore-publiccloud-lax.contextbuilder=org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXContextBuilder dunkel-vcd.propertiesbuilder=org.jclouds.dunkel.vcd.DunkelVCloudDirectorPropertiesBuilder dunkel-vcd.contextbuilder=org.jclouds.dunkel.vcd.DunkelVCloudDirectorContextBuilder diff --git a/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java b/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java index e0d12c3c6d..7ba53f8131 100644 --- a/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java +++ b/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java @@ -33,11 +33,6 @@ public class BluelockVCloudZone01ComputeServiceLiveTest extends VCloudComputeSer public BluelockVCloudZone01ComputeServiceLiveTest() { provider = "bluelock-vcloud-zone01"; } - - @Override - public void setServiceDefaults() { - group = "director"; - } protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) { // hostname is not completely predictable based on node metadata diff --git a/providers/greenhousedata-element-vcloud/pom.xml b/providers/greenhousedata-element-vcloud/pom.xml index bf3944e966..f407917b6c 100644 --- a/providers/greenhousedata-element-vcloud/pom.xml +++ b/providers/greenhousedata-element-vcloud/pom.xml @@ -40,6 +40,8 @@ FIXME_IDENTITY FIXME_CREDENTIAL + + @@ -106,6 +108,8 @@ ${test.greenhousedata-element-vcloud.identity} ${test.greenhousedata-element-vcloud.credential} ${test.greenhousedata-element-vcloud.image-id} + ${test.greenhousedata-element-vcloud.image.login-user} + ${test.greenhousedata-element-vcloud.image.authenticate-sudo} diff --git a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java index 5aab18ac13..679d1b462f 100644 --- a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java +++ b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/compute/GreenHouseDataElementVCloudComputeServiceLiveTest.java @@ -18,8 +18,6 @@ */ package org.jclouds.greenhousedata.element.vcloud.compute; -import org.jclouds.compute.domain.ExecResponse; -import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest; import org.testng.annotations.Test; @@ -32,17 +30,6 @@ import org.testng.annotations.Test; public class GreenHouseDataElementVCloudComputeServiceLiveTest extends VCloudComputeServiceLiveTest { public GreenHouseDataElementVCloudComputeServiceLiveTest() { provider = "greenhousedata-element-vcloud"; - // vcloud requires instantiate before deploy, which takes longer than 30 seconds - nonBlockDurationSeconds = 300; } - - @Override - public void setServiceDefaults() { - group = "director"; - } - - protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) { - // hostname is not predictable based on node metadata - assert execResponse.getOutput().trim().equals("(none)"); - } -} + +} \ No newline at end of file diff --git a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java index 24eaf287a4..4527c2e726 100644 --- a/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java +++ b/providers/greenhousedata-element-vcloud/src/test/java/org/jclouds/greenhousedata/element/vcloud/features/GreenHouseDataElementVCloudVmClientLiveTest.java @@ -18,7 +18,6 @@ */ package org.jclouds.greenhousedata.element.vcloud.features; -import org.jclouds.compute.domain.ExecResponse; import org.jclouds.vcloud.features.VmClientLiveTest; import org.testng.annotations.Test; @@ -33,15 +32,5 @@ public class GreenHouseDataElementVCloudVmClientLiveTest extends VmClientLiveTes public GreenHouseDataElementVCloudVmClientLiveTest() { provider = "greenhousedata-element-vcloud"; } - - @Override - protected void checkApiOutput(String apiOutput) { - checkApiOutput1_0_0(apiOutput); - } - @Override - protected void checkCustomizationOccurred(ExecResponse exec) { - // for some reason customization doesn't actually occur - assert exec.getOutput().equals("") : exec; - } } diff --git a/providers/stratogen-vcloud-mycloud/pom.xml b/providers/stratogen-vcloud-mycloud/pom.xml index 39e17a87af..6e51617c86 100644 --- a/providers/stratogen-vcloud-mycloud/pom.xml +++ b/providers/stratogen-vcloud-mycloud/pom.xml @@ -36,10 +36,12 @@ https://vcd.stratogen.net/api 1.0 - + 1.5.0.464915 FIXME_IDENTITY FIXME_CREDENTIAL + + @@ -106,6 +108,8 @@ ${test.stratogen-vcloud-mycloud.identity} ${test.stratogen-vcloud-mycloud.credential} ${test.stratogen-vcloud-mycloud.image-id} + ${test.stratogen-vcloud-mycloud.image.login-user} + ${test.stratogen-vcloud-mycloud.image.authenticate-sudo} diff --git a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java index 2ce7fe0656..ddcd6bed32 100644 --- a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java +++ b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/StratoGenVCloudMyCloudPropertiesBuilder.java @@ -18,6 +18,7 @@ */ package org.jclouds.stratogen.vcloud.mycloud; +import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK; @@ -37,6 +38,7 @@ public class StratoGenVCloudMyCloudPropertiesBuilder extends VCloudPropertiesBui Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_ISO3166_CODES, "GB"); properties.setProperty(PROPERTY_ENDPOINT, "https://vcd.stratogen.net/api"); + properties.setProperty(PROPERTY_BUILD_VERSION, "1.5.0.464915"); properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, "Direct Internet"); return properties; } diff --git a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java index 56e5134a18..a10b42fc0d 100644 --- a/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java +++ b/providers/stratogen-vcloud-mycloud/src/main/java/org/jclouds/stratogen/vcloud/mycloud/config/StratoGenVCloudMyCloudComputeServiceContextModule.java @@ -18,6 +18,7 @@ */ package org.jclouds.stratogen.vcloud.mycloud.config; +import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule; import org.jclouds.vcloud.compute.options.VCloudTemplateOptions; @@ -31,6 +32,12 @@ import com.google.inject.Injector; * @author Adrian Cole */ public class StratoGenVCloudMyCloudComputeServiceContextModule extends VCloudComputeServiceContextModule { + + @Override + protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) { + return template.imageNameMatches("Ubuntu server 11.04 64bit no GUI (base)"); + } + @Override protected TemplateOptions provideTemplateOptions(Injector injector, TemplateOptions options) { return options.as(VCloudTemplateOptions.class).ipAddressAllocationMode(IpAddressAllocationMode.POOL); diff --git a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java index 33222f6ff2..941b72bac6 100644 --- a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java +++ b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudComputeServiceLiveTest.java @@ -18,16 +18,8 @@ */ package org.jclouds.stratogen.vcloud.mycloud.compute; -import static org.jclouds.compute.util.ComputeServiceUtils.getCores; -import static org.testng.Assert.assertEquals; - import org.jclouds.compute.domain.ExecResponse; -import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.domain.OsFamily; -import org.jclouds.compute.domain.Template; -import org.jclouds.compute.domain.TemplateBuilder; -import org.jclouds.compute.predicates.OperatingSystemPredicates; import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest; import org.testng.annotations.Test; @@ -40,34 +32,6 @@ import org.testng.annotations.Test; public class StratoGenVCloudMyCloudComputeServiceLiveTest extends VCloudComputeServiceLiveTest { public StratoGenVCloudMyCloudComputeServiceLiveTest() { provider = "stratogen-vcloud-mycloud"; - // vcloud requires instantiate before deploy, which takes longer than 30 - // seconds - nonBlockDurationSeconds = 300; - } - - @Override - public void setServiceDefaults() { - group = "director"; - } - - @Test - public void testTemplateBuilder() { - Template defaultTemplate = client.templateBuilder().build(); - assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); - assert OperatingSystemPredicates.supportsApt().apply(defaultTemplate.getImage().getOperatingSystem()); - assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); - assertEquals(defaultTemplate.getImage().getOperatingSystem().getDescription(), "Ubuntu Linux (64-bit)"); - assert defaultTemplate.getLocation().getId() != null : defaultTemplate.getLocation(); - assertEquals(getCores(defaultTemplate.getHardware()), 1.0d); - System.out.println(defaultTemplate.getHardware()); - } - - @Override - protected Template buildTemplate(TemplateBuilder templateBuilder) { - Template template = super.buildTemplate(templateBuilder); - Image image = template.getImage(); - assert image.getDefaultCredentials().credential != null : image; - return template; } protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) { diff --git a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java index 090752377d..5d03161fe5 100644 --- a/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java +++ b/providers/stratogen-vcloud-mycloud/src/test/java/org/jclouds/stratogen/vcloud/mycloud/compute/StratoGenVCloudMyCloudTemplateBuilderLiveTest.java @@ -31,6 +31,7 @@ import org.jclouds.compute.domain.Template; import org.testng.annotations.Test; import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import com.google.common.collect.ImmutableSet; /** @@ -46,24 +47,31 @@ public class StratoGenVCloudMyCloudTemplateBuilderLiveTest extends BaseTemplateB @Override protected Predicate defineUnsupportedOperatingSystems() { - return new Predicate() { + return Predicates.not(new Predicate() { @Override public boolean apply(OsFamilyVersion64Bit input) { switch (input.family) { case UBUNTU: - return !input.version.equals("") || !input.is64Bit; + return input.version.equals(""); + case DEBIAN: + return input.version.equals("") && !input.is64Bit; + case RHEL: + return input.version.equals("") && input.is64Bit; + case WINDOWS: + return input.version.equals("") && input.is64Bit; default: - return true; + return false; } } - }; + }); } @Override public void testDefaultTemplateBuilder() throws IOException { Template defaultTemplate = context.getComputeService().templateBuilder().build(); + assertEquals(defaultTemplate.getImage().getName(), "Ubuntu server 11.04 64bit no GUI (base)"); assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), ""); assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); diff --git a/sandbox-providers/dunkel-vcd/pom.xml b/sandbox-providers/dunkel-vcd/pom.xml index 71d887b0d9..99a564c8d7 100644 --- a/sandbox-providers/dunkel-vcd/pom.xml +++ b/sandbox-providers/dunkel-vcd/pom.xml @@ -35,10 +35,12 @@ https://vcd.dunkel.de/api 1.0 - + 1.0.1.356485 FIXME_IDENTITY FIXME_CREDENTIAL + + @@ -98,14 +100,16 @@ test - - ${test.dunkel-vcd.endpoint} - ${test.dunkel-vcd.api-version} - ${test.dunkel-vcd.build-version} - ${test.dunkel-vcd.identity} - ${test.dunkel-vcd.credential} - ${test.dunkel-vcd.image-id} - + + ${test.dunkel-vcd.endpoint} + ${test.dunkel-vcd.api-version} + ${test.dunkel-vcd.build-version} + ${test.dunkel-vcd.identity} + ${test.dunkel-vcd.credential} + ${test.dunkel-vcd.image-id} + ${test.dunkel-vcd.image.login-user} + ${test.dunkel-vcd.image.authenticate-sudo} + @@ -115,6 +119,21 @@ + + + + org.apache.felix + maven-bundle-plugin + + + ${project.artifactId} + org.jclouds.dunkel.vcd.*;version="${project.version}" + org.jclouds.*;version="${project.version}",* + + + + + diff --git a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java index fcd3773452..29521af599 100644 --- a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java +++ b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/DunkelVCloudDirectorPropertiesBuilder.java @@ -18,6 +18,7 @@ */ package org.jclouds.dunkel.vcd; +import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK; @@ -35,6 +36,7 @@ public class DunkelVCloudDirectorPropertiesBuilder extends VCloudPropertiesBuild protected Properties defaultProperties() { Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_ISO3166_CODES, "DE"); + properties.setProperty(PROPERTY_BUILD_VERSION, "1.0.1.356485"); properties.setProperty(PROPERTY_ENDPOINT, "https://vcd.dunkel.de/api"); properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, ".*-intranet"); return properties; diff --git a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java index 9a1e1ed607..1c6aba2d37 100644 --- a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java +++ b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/config/DunkelVCloudDirectorRestClientModule.java @@ -21,8 +21,6 @@ package org.jclouds.dunkel.vcd.config; import org.jclouds.http.RequiresHttp; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.vcloud.config.VCloudRestClientModule; -import org.jclouds.vcloud.filters.SetVCloudTokenCookie; -import org.jclouds.dunkel.vcd.filters.SetVCloudTokenCookieAndAuthorizationHeader; /** * @@ -32,10 +30,4 @@ import org.jclouds.dunkel.vcd.filters.SetVCloudTokenCookieAndAuthorizationHeader @ConfiguresRestClient public class DunkelVCloudDirectorRestClientModule extends VCloudRestClientModule { - @Override - protected void configure() { - super.configure(); - bind(SetVCloudTokenCookie.class).to(SetVCloudTokenCookieAndAuthorizationHeader.class); - } - } diff --git a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/filters/SetVCloudTokenCookieAndAuthorizationHeader.java b/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/filters/SetVCloudTokenCookieAndAuthorizationHeader.java deleted file mode 100644 index 746d0d51b1..0000000000 --- a/sandbox-providers/dunkel-vcd/src/main/java/org/jclouds/dunkel/vcd/filters/SetVCloudTokenCookieAndAuthorizationHeader.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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.dunkel.vcd.filters; - -import javax.inject.Inject; -import javax.inject.Provider; -import javax.inject.Singleton; - -import org.jclouds.http.HttpException; -import org.jclouds.http.HttpRequest; -import org.jclouds.http.utils.ModifyRequest; -import org.jclouds.vcloud.VCloudToken; -import org.jclouds.vcloud.filters.SetVCloudTokenCookie; - -/** - * Adds the VCloud Token to the request as a cookie - * - * @author Adrian Cole - * - */ -@Singleton -public class SetVCloudTokenCookieAndAuthorizationHeader extends SetVCloudTokenCookie { - - private final Provider vcloudTokenProvider; - - @Inject - public SetVCloudTokenCookieAndAuthorizationHeader(@VCloudToken Provider authTokenProvider) { - super(authTokenProvider); - this.vcloudTokenProvider = authTokenProvider; - } - - @Override - public HttpRequest filter(HttpRequest request) throws HttpException { - return ModifyRequest.replaceHeader(super.filter(request), "x-vcloud-authorization", vcloudTokenProvider.get()); - } - -} diff --git a/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java b/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java index 2657004a8b..d5e46c831b 100644 --- a/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java +++ b/sandbox-providers/dunkel-vcd/src/test/java/org/jclouds/dunkel/vcd/compute/DunkelVCloudDirectorComputeServiceLiveTest.java @@ -32,9 +32,4 @@ public class DunkelVCloudDirectorComputeServiceLiveTest extends VCloudComputeSer provider = "dunkel-vcd"; } - @Override - public void setServiceDefaults() { - group = "director"; - } - } diff --git a/sandbox-providers/virtacore-vcloudexpress/pom.xml b/sandbox-providers/virtacore-publiccloud-lax/pom.xml similarity index 55% rename from sandbox-providers/virtacore-vcloudexpress/pom.xml rename to sandbox-providers/virtacore-publiccloud-lax/pom.xml index a2a0d29e75..6a8b7921d5 100644 --- a/sandbox-providers/virtacore-vcloudexpress/pom.xml +++ b/sandbox-providers/virtacore-publiccloud-lax/pom.xml @@ -28,17 +28,17 @@ ../../project/pom.xml org.jclouds.provider - virtacore-vcloudexpress - jclouds Virtacore vCloud Express provider - vCloud implementation targeted to Virtacore + virtacore-publiccloud-lax + jclouds Virtacore Public Cloud LAX provider + vCloud implementation targeted to Virtacore's LAX datacenter - https://vcloud.virtacore.com/api - 1.0 - - FIXME_IDENTITY - FIXME_CREDENTIAL - + https://cloud.lax.virtacore.com/api/ + 1.0 + 1.5.0.464915 + FIXME_IDENTITY + FIXME_CREDENTIAL + @@ -99,12 +99,15 @@ - ${test.virtacore-vcloudexpress.endpoint} - ${test.virtacore-vcloudexpress.api-version} - ${test.virtacore-vcloudexpress.build-version} - ${test.virtacore-vcloudexpress.identity} - ${test.virtacore-vcloudexpress.credential} - ${test.virtacore-vcloudexpress.image-id} + ${test.virtacore-publiccloud-lax.endpoint} + ${test.virtacore-publiccloud-lax.api-version} + ${test.virtacore-publiccloud-lax.build-version} + ${test.virtacore-publiccloud-lax.identity} + ${test.virtacore-publiccloud-lax.credential} + ${test.virtacore-publiccloud-lax.image-id} + ${test.virtacore-publiccloud-lax.image-id} + ${test.virtacore-publiccloud-lax.image.login-user} + ${test.virtacore-publiccloud-lax.image.authenticate-sudo} @@ -116,5 +119,20 @@ + + + + org.apache.felix + maven-bundle-plugin + + + ${project.artifactId} + org.jclouds.virtacore.publiccloud.*;version="${project.version}" + org.jclouds.*;version="${project.version}",* + + + + + diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressContextBuilder.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXContextBuilder.java similarity index 68% rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressContextBuilder.java rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXContextBuilder.java index 05dde33f7d..15ce9efcd2 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressContextBuilder.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXContextBuilder.java @@ -16,14 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress; +package org.jclouds.virtacore.publiccloud; import java.util.List; import java.util.Properties; import org.jclouds.vcloud.VCloudContextBuilder; -import org.jclouds.virtacore.vcloudexpress.config.VirtacoreVCloudExpressComputeServiceContextModule; -import org.jclouds.virtacore.vcloudexpress.config.VirtacoreVCloudExpressRestClientModule; +import org.jclouds.virtacore.publiccloud.config.VirtacorePublicCloudLAXComputeServiceContextModule; +import org.jclouds.virtacore.publiccloud.config.VirtacorePublicCloudLAXRestClientModule; import com.google.inject.Module; @@ -32,20 +32,20 @@ import com.google.inject.Module; * @author Adrian Cole * */ -public class VirtacoreVCloudExpressContextBuilder extends VCloudContextBuilder { +public class VirtacorePublicCloudLAXContextBuilder extends VCloudContextBuilder { - public VirtacoreVCloudExpressContextBuilder(Properties props) { + public VirtacorePublicCloudLAXContextBuilder(Properties props) { super(props); } @Override protected void addContextModule(List modules) { - modules.add(new VirtacoreVCloudExpressComputeServiceContextModule()); + modules.add(new VirtacorePublicCloudLAXComputeServiceContextModule()); } @Override protected void addClientModule(List modules) { - modules.add(new VirtacoreVCloudExpressRestClientModule()); + modules.add(new VirtacorePublicCloudLAXRestClientModule()); } } diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressPropertiesBuilder.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXPropertiesBuilder.java similarity index 67% rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressPropertiesBuilder.java rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXPropertiesBuilder.java index f428fb6676..804de5c84c 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressPropertiesBuilder.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXPropertiesBuilder.java @@ -16,10 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress; +package org.jclouds.virtacore.publiccloud; +import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; +import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_CATALOG; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK; import java.util.Properties; @@ -30,17 +32,19 @@ import org.jclouds.vcloud.VCloudPropertiesBuilder; * * @author Adrian Cole */ -public class VirtacoreVCloudExpressPropertiesBuilder extends VCloudPropertiesBuilder { +public class VirtacorePublicCloudLAXPropertiesBuilder extends VCloudPropertiesBuilder { @Override protected Properties defaultProperties() { Properties properties = super.defaultProperties(); - properties.setProperty(PROPERTY_ISO3166_CODES, "US-VA,US-CA"); - properties.setProperty(PROPERTY_ENDPOINT, "https://vcloud.virtacore.com/api"); + properties.setProperty(PROPERTY_ISO3166_CODES, "US-CA"); + properties.setProperty(PROPERTY_ENDPOINT, "https://cloud.lax.virtacore.com/api"); + properties.setProperty(PROPERTY_BUILD_VERSION, "1.5.0.464915"); properties.setProperty(PROPERTY_VCLOUD_DEFAULT_NETWORK, ".*-Public"); + properties.setProperty(PROPERTY_VCLOUD_DEFAULT_CATALOG, "Virtacore Templates - .*"); return properties; } - public VirtacoreVCloudExpressPropertiesBuilder(Properties properties) { + public VirtacorePublicCloudLAXPropertiesBuilder(Properties properties) { super(properties); } } diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderMetadata.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderMetadata.java similarity index 82% rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderMetadata.java rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderMetadata.java index 6093dcb5fd..1f06295497 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderMetadata.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderMetadata.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress; +package org.jclouds.virtacore.publiccloud; import com.google.common.collect.ImmutableSet; @@ -27,18 +27,18 @@ import org.jclouds.providers.BaseProviderMetadata; import org.jclouds.providers.ProviderMetadata; /** - * Implementation of {@link org.jclouds.types.ProviderMetadata} for Virtacore vCloud Express + * Implementation of {@link org.jclouds.types.ProviderMetadata} for Virtacore Public Cloud LAX * * @author Adrian Cole */ -public class VirtacoreVCloudExpressProviderMetadata extends BaseProviderMetadata { +public class VirtacorePublicCloudLAXProviderMetadata extends BaseProviderMetadata { /** * {@inheritDoc} */ @Override public String getId() { - return "virtacore-vcloudexpress"; + return "virtacore-publiccloud-lax"; } /** @@ -54,7 +54,7 @@ public class VirtacoreVCloudExpressProviderMetadata extends BaseProviderMetadata */ @Override public String getName() { - return "Virtacore vCloud Express"; + return "Virtacore Public Cloud LAX"; } /** @@ -94,7 +94,7 @@ public class VirtacoreVCloudExpressProviderMetadata extends BaseProviderMetadata */ @Override public URI getApiDocumentation() { - return URI.create("http://kb.virtacore.com/categories/vCloud+Express/"); + return URI.create("http://kb.virtacore.com/questions/100/Does+the+Virtacore+Public+Cloud+have+an+API%3F"); } /** @@ -102,7 +102,7 @@ public class VirtacoreVCloudExpressProviderMetadata extends BaseProviderMetadata */ @Override public Set getLinkedServices() { - return ImmutableSet.of("virtacore-vcloudexpress"); + return ImmutableSet.of("virtacore-publiccloud-lax", "virtacore-publiccloud-iad"); } /** @@ -110,7 +110,7 @@ public class VirtacoreVCloudExpressProviderMetadata extends BaseProviderMetadata */ @Override public Set getIso3166Codes() { - return ImmutableSet.of("US-VA","US-CA"); + return ImmutableSet.of("US-CA"); } } diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressComputeServiceContextModule.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXComputeServiceContextModule.java similarity index 73% rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressComputeServiceContextModule.java rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXComputeServiceContextModule.java index 2fc627199c..d139aafe4c 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressComputeServiceContextModule.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXComputeServiceContextModule.java @@ -16,8 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress.config; +package org.jclouds.virtacore.publiccloud.config; +import static org.jclouds.compute.domain.OsFamily.RHEL; + +import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule; import org.jclouds.vcloud.compute.options.VCloudTemplateOptions; @@ -29,8 +32,14 @@ import com.google.inject.Injector; * * @author Adrian Cole */ -public class VirtacoreVCloudExpressComputeServiceContextModule extends VCloudComputeServiceContextModule { - +public class VirtacorePublicCloudLAXComputeServiceContextModule extends VCloudComputeServiceContextModule { + + // CIM ostype does not include version info + @Override + protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) { + return template.osFamily(RHEL).os64Bit(true); + } + @Override protected TemplateOptions provideTemplateOptions(Injector injector, TemplateOptions options) { return options.as(VCloudTemplateOptions.class).ipAddressAllocationMode(IpAddressAllocationMode.POOL); diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressRestClientModule.java b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXRestClientModule.java similarity index 74% rename from sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressRestClientModule.java rename to sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXRestClientModule.java index 1b1e3b803d..e089e92928 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/config/VirtacoreVCloudExpressRestClientModule.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/java/org/jclouds/virtacore/publiccloud/config/VirtacorePublicCloudLAXRestClientModule.java @@ -16,13 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress.config; +package org.jclouds.virtacore.publiccloud.config; import org.jclouds.http.RequiresHttp; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.vcloud.config.VCloudRestClientModule; -import org.jclouds.vcloud.filters.SetVCloudTokenCookie; -import org.jclouds.virtacore.vcloudexpress.filters.SetVCloudTokenCookieAndAuthorizationHeader; /** * @@ -30,12 +28,11 @@ import org.jclouds.virtacore.vcloudexpress.filters.SetVCloudTokenCookieAndAuthor */ @RequiresHttp @ConfiguresRestClient -public class VirtacoreVCloudExpressRestClientModule extends VCloudRestClientModule { +public class VirtacorePublicCloudLAXRestClientModule extends VCloudRestClientModule { @Override protected void configure() { super.configure(); - bind(SetVCloudTokenCookie.class).to(SetVCloudTokenCookieAndAuthorizationHeader.class); } } diff --git a/sandbox-providers/virtacore-publiccloud-lax/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/sandbox-providers/virtacore-publiccloud-lax/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata new file mode 100644 index 0000000000..5290e8f3d0 --- /dev/null +++ b/sandbox-providers/virtacore-publiccloud-lax/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata @@ -0,0 +1 @@ +org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXProviderMetadata diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderTest.java b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderTest.java similarity index 69% rename from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderTest.java rename to sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderTest.java index 8965a26a6e..687b7d91f9 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/VirtacoreVCloudExpressProviderTest.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/VirtacorePublicCloudLAXProviderTest.java @@ -16,21 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress; +package org.jclouds.virtacore.publiccloud; import org.jclouds.providers.BaseProviderMetadataTest; import org.jclouds.providers.ProviderMetadata; -import org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressProviderMetadata; +import org.jclouds.virtacore.publiccloud.VirtacorePublicCloudLAXProviderMetadata; import org.testng.annotations.Test; /** * * @author Adrian Cole */ -@Test(groups = "unit", testName = "VirtacoreVCloudExpressProviderTest") -public class VirtacoreVCloudExpressProviderTest extends BaseProviderMetadataTest { +@Test(groups = "unit", testName = "VirtacorePublicCloudLAXProviderTest") +public class VirtacorePublicCloudLAXProviderTest extends BaseProviderMetadataTest { - public VirtacoreVCloudExpressProviderTest() { - super(new VirtacoreVCloudExpressProviderMetadata(), ProviderMetadata.COMPUTE_TYPE); + public VirtacorePublicCloudLAXProviderTest() { + super(new VirtacorePublicCloudLAXProviderMetadata(), ProviderMetadata.COMPUTE_TYPE); } } diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXComputeServiceLiveTest.java similarity index 74% rename from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java rename to sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXComputeServiceLiveTest.java index a172d5f58c..ae8c1531b7 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressComputeServiceLiveTest.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXComputeServiceLiveTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress.compute; +package org.jclouds.virtacore.publiccloud.compute; import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest; import org.testng.annotations.Test; @@ -27,14 +27,9 @@ import org.testng.annotations.Test; * @author Adrian Cole */ @Test(groups = "live", enabled = true, singleThreaded = true) -public class VirtacoreVCloudExpressComputeServiceLiveTest extends VCloudComputeServiceLiveTest { - public VirtacoreVCloudExpressComputeServiceLiveTest() { - provider = "virtacore-vcloudexpress"; - } - - @Override - public void setServiceDefaults() { - group = "director"; +public class VirtacorePublicCloudLAXComputeServiceLiveTest extends VCloudComputeServiceLiveTest { + public VirtacorePublicCloudLAXComputeServiceLiveTest() { + provider = "virtacore-publiccloud-lax"; } } diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressTemplateBuilderLiveTest.java b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXTemplateBuilderLiveTest.java similarity index 69% rename from sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressTemplateBuilderLiveTest.java rename to sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXTemplateBuilderLiveTest.java index d45cfef9a1..4f8b410ce6 100644 --- a/sandbox-providers/virtacore-vcloudexpress/src/test/java/org/jclouds/virtacore/vcloudexpress/compute/VirtacoreVCloudExpressTemplateBuilderLiveTest.java +++ b/sandbox-providers/virtacore-publiccloud-lax/src/test/java/org/jclouds/virtacore/publiccloud/compute/VirtacorePublicCloudLAXTemplateBuilderLiveTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtacore.vcloudexpress.compute; +package org.jclouds.virtacore.publiccloud.compute; import static org.jclouds.compute.util.ComputeServiceUtils.getCores; import static org.testng.Assert.assertEquals; @@ -31,6 +31,7 @@ import org.jclouds.compute.domain.Template; import org.testng.annotations.Test; import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import com.google.common.collect.ImmutableSet; /** @@ -38,42 +39,45 @@ import com.google.common.collect.ImmutableSet; * @author Adrian Cole */ @Test(groups = "live") -public class VirtacoreVCloudExpressTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { +public class VirtacorePublicCloudLAXTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { - public VirtacoreVCloudExpressTemplateBuilderLiveTest() { - provider = "virtacore-vcloudexpress"; + public VirtacorePublicCloudLAXTemplateBuilderLiveTest() { + provider = "virtacore-publiccloud-lax"; } @Override protected Predicate defineUnsupportedOperatingSystems() { - return new Predicate() { + return Predicates.not(new Predicate() { @Override public boolean apply(OsFamilyVersion64Bit input) { switch (input.family) { - case UBUNTU: - return !input.version.equals(""); - case RHEL: - return !input.version.equals(""); - default: - return true; + case RHEL: + return input.version.equals(""); + case SUSE: + // vCloud Connector + return input.version.equals("") && input.is64Bit; + default: + return false; } } - }; + }); } + // NOTE: almost all virtacore templates are dual-network @Override public void testDefaultTemplateBuilder() throws IOException { Template defaultTemplate = context.getComputeService().templateBuilder().build(); + assertEquals(defaultTemplate.getImage().getName(), "RHEL 5.6 64bit"); assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), ""); assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); - assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); - assertEquals(getCores(defaultTemplate.getHardware()), 1.0d); + assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.RHEL); + assertEquals(getCores(defaultTemplate.getHardware()), 2.0d); } @Override protected Set getIso3166Codes() { - return ImmutableSet. of("US-VA", "US-CA"); + return ImmutableSet. of("US-CA"); } } diff --git a/sandbox-providers/virtacore-vcloudexpress/src/test/resources/log4j.xml b/sandbox-providers/virtacore-publiccloud-lax/src/test/resources/log4j.xml similarity index 100% rename from sandbox-providers/virtacore-vcloudexpress/src/test/resources/log4j.xml rename to sandbox-providers/virtacore-publiccloud-lax/src/test/resources/log4j.xml diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/filters/SetVCloudTokenCookieAndAuthorizationHeader.java b/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/filters/SetVCloudTokenCookieAndAuthorizationHeader.java deleted file mode 100644 index c87597bd3f..0000000000 --- a/sandbox-providers/virtacore-vcloudexpress/src/main/java/org/jclouds/virtacore/vcloudexpress/filters/SetVCloudTokenCookieAndAuthorizationHeader.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 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.virtacore.vcloudexpress.filters; - -import javax.inject.Inject; -import javax.inject.Provider; -import javax.inject.Singleton; - -import org.jclouds.http.HttpException; -import org.jclouds.http.HttpRequest; -import org.jclouds.http.utils.ModifyRequest; -import org.jclouds.vcloud.VCloudToken; -import org.jclouds.vcloud.filters.SetVCloudTokenCookie; - -/** - * Adds the VCloud Token to the request as a cookie - * - * @author Adrian Cole - * - */ -@Singleton -public class SetVCloudTokenCookieAndAuthorizationHeader extends SetVCloudTokenCookie { - - private final Provider vcloudTokenProvider; - - @Inject - public SetVCloudTokenCookieAndAuthorizationHeader(@VCloudToken Provider authTokenProvider) { - super(authTokenProvider); - this.vcloudTokenProvider = authTokenProvider; - } - - @Override - public HttpRequest filter(HttpRequest request) throws HttpException { - return ModifyRequest.replaceHeader(super.filter(request), "x-vcloud-authorization", vcloudTokenProvider.get()); - } - -} \ No newline at end of file diff --git a/sandbox-providers/virtacore-vcloudexpress/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/sandbox-providers/virtacore-vcloudexpress/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata deleted file mode 100644 index 8505807ce7..0000000000 --- a/sandbox-providers/virtacore-vcloudexpress/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata +++ /dev/null @@ -1 +0,0 @@ -org.jclouds.virtacore.vcloudexpress.VirtacoreVCloudExpressProviderMetadata From de1e8a7ce3491debafc9a489f3b58556126bb349 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 02:19:05 -0800 Subject: [PATCH 67/82] avoid stackoverflow on multipart upload --- .../strategy/internal/SequentialMultipartUploadStrategy.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java index 1198c23466..e4ffc25a27 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java @@ -126,7 +126,8 @@ public class SequentialMultipartUploadStrategy implements MultipartUploadStrateg throw rtex; } } else { - return ablobstore.putBlob(container, blob, options); + // TODO: find a way to disable multipart. if we pass the original options, it goes into a stack overflow + return ablobstore.putBlob(container, blob, PutOptions.NONE); } } } From 63320f15b61466c66cdbd8ba96a420641371c7a4 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 11:30:22 -0800 Subject: [PATCH 68/82] Issue 731: unravel dependency cycle to only use interfaces --- ...BaseCloudLoadBalancersAsyncClientTest.java | 3 +- .../config/OpenStackAuthenticationModule.java | 79 +++++------ .../openstack/handlers/RetryOnRenew.java | 15 +-- .../openstack/handlers/RetryOnRenewTest.java | 15 ++- .../RetryOnTimeOutExceptionFunction.java | 77 +++++++++++ .../RetryOnTimeOutExceptionFunctionTest.java | 126 ++++++++++++++++++ 6 files changed, 256 insertions(+), 59 deletions(-) create mode 100644 core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunction.java create mode 100644 core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunctionTest.java diff --git a/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java b/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java index 05280b785e..a619a26b87 100644 --- a/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java +++ b/apis/cloudloadbalancers/src/test/java/org/jclouds/cloudloadbalancers/features/BaseCloudLoadBalancersAsyncClientTest.java @@ -30,6 +30,7 @@ import org.jclouds.cloudloadbalancers.CloudLoadBalancersClient; import org.jclouds.cloudloadbalancers.config.CloudLoadBalancersRestClientModule; import org.jclouds.cloudloadbalancers.functions.ConvertLB; import org.jclouds.cloudloadbalancers.reference.Region; +import org.jclouds.domain.Credentials; import org.jclouds.http.HttpRequest; import org.jclouds.http.RequiresHttp; import org.jclouds.internal.ClassMethodArgs; @@ -78,7 +79,7 @@ public abstract class BaseCloudLoadBalancersAsyncClientTest extends RestClien install(new OpenStackAuthenticationModule() { @Override protected Supplier provideAuthenticationResponseSupplier( - final LoadingCache cache) { + LoadingCache cache, Credentials in) { return Suppliers.ofInstance(new AuthenticationResponse("token", ImmutableMap. of())); } }); diff --git a/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java b/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java index e7f180d312..0d260b205b 100644 --- a/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java +++ b/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java @@ -29,14 +29,17 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.Constants; -import org.jclouds.concurrent.RetryOnTimeOutExceptionSupplier; +import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction; import org.jclouds.date.TimeStamp; +import org.jclouds.domain.Credentials; import org.jclouds.http.RequiresHttp; +import org.jclouds.location.Provider; import org.jclouds.openstack.Authentication; import org.jclouds.openstack.OpenStackAuthAsyncClient; import org.jclouds.openstack.OpenStackAuthAsyncClient.AuthenticationResponse; import org.jclouds.rest.AsyncClientFactory; +import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.base.Throwables; @@ -46,6 +49,7 @@ import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.UncheckedExecutionException; import com.google.inject.AbstractModule; import com.google.inject.Provides; +import com.google.inject.TypeLiteral; /** * Configures the Rackspace authentication service connection, including logging and http transport. @@ -57,6 +61,8 @@ public class OpenStackAuthenticationModule extends AbstractModule { @Override protected void configure() { + bind(new TypeLiteral>() { + }).to(GetAuthenticationResponse.class); } /** @@ -74,68 +80,57 @@ public class OpenStackAuthenticationModule extends AbstractModule { }; } + @Provides + @Provider + protected Credentials provideAuthenticationCredentials(@Named(Constants.PROPERTY_IDENTITY) String user, + @Named(Constants.PROPERTY_CREDENTIAL) String key) { + return new Credentials(user, key); + } + @Singleton - public static class GetAuthenticationResponse implements Supplier { - protected final OpenStackAuthAsyncClient client; - protected final String user; - protected final String key; + public static class GetAuthenticationResponse extends + RetryOnTimeOutExceptionFunction { @Inject - public GetAuthenticationResponse(AsyncClientFactory factory, @Named(Constants.PROPERTY_IDENTITY) String user, - @Named(Constants.PROPERTY_CREDENTIAL) String key) { - this.client = factory.create(OpenStackAuthAsyncClient.class); - this.user = user; - this.key = key; - } + public GetAuthenticationResponse(final AsyncClientFactory factory) { + super(new Function() { - @Override - public AuthenticationResponse get() { - try { - Future response = authenticate(); - return response.get(30, TimeUnit.SECONDS); - } catch (Exception e) { - Throwables.propagate(e); - assert false : e; - return null; - } - } + @Override + public AuthenticationResponse apply(Credentials input) { + try { + Future response = factory.create(OpenStackAuthAsyncClient.class) + .authenticate(input.identity, input.credential); + return response.get(30, TimeUnit.SECONDS); + } catch (Exception e) { + throw Throwables.propagate(e); + } + } + }); - protected Future authenticate() { - return client.authenticate(user, key); } - } @Provides @Singleton - public LoadingCache provideAuthenticationResponseCache2( - final GetAuthenticationResponse getAuthenticationResponse) { - - final RetryOnTimeOutExceptionSupplier delegate = - new RetryOnTimeOutExceptionSupplier(getAuthenticationResponse); + public LoadingCache provideAuthenticationResponseCache2( + final Function getAuthenticationResponse, + @Provider final Credentials creds) { + + LoadingCache cache = CacheBuilder.newBuilder().expireAfterWrite(23, + TimeUnit.HOURS).build(CacheLoader.from(getAuthenticationResponse)); - CacheLoader cacheLoader = new CacheLoader() { - @Override - public AuthenticationResponse load(String key) throws Exception { - return delegate.get(); - } - }; - - LoadingCache cache = CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS) - .build(cacheLoader); - return cache; } @Provides @Singleton protected Supplier provideAuthenticationResponseSupplier( - final LoadingCache cache) { + final LoadingCache cache, @Provider final Credentials creds) { return new Supplier() { @Override public AuthenticationResponse get() { try { - return cache.get("key"); + return cache.get(creds); } catch (UncheckedExecutionException e) { throw Throwables.propagate(e.getCause()); } catch (ExecutionException e) { diff --git a/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java b/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java index edb39e1a38..dc0cb7e6da 100644 --- a/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java +++ b/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java @@ -24,6 +24,7 @@ import java.io.IOException; import javax.annotation.Resource; +import org.jclouds.domain.Credentials; import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpRetryHandler; @@ -48,12 +49,8 @@ public class RetryOnRenew implements HttpRetryHandler { @Resource protected Logger logger = Logger.NULL; - // This doesn't work yet -// @Inject -// Supplier providedAuthenticationResponseCache; - @Inject - LoadingCache authenticationResponseCache; + LoadingCache authenticationResponseCache; @Override public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) { @@ -63,8 +60,8 @@ public class RetryOnRenew implements HttpRetryHandler { case 401: // Do not retry on 401 from authentication request Multimap headers = command.getCurrentRequest().getHeaders(); - if (headers != null && headers.containsKey(AuthHeaders.AUTH_USER) && headers.containsKey(AuthHeaders.AUTH_KEY) && - !headers.containsKey(AuthHeaders.AUTH_TOKEN)) { + if (headers != null && headers.containsKey(AuthHeaders.AUTH_USER) + && headers.containsKey(AuthHeaders.AUTH_KEY) && !headers.containsKey(AuthHeaders.AUTH_TOKEN)) { retry = false; } else { String content = parsePayloadOrNull(response); @@ -79,12 +76,12 @@ public class RetryOnRenew implements HttpRetryHandler { break; } return retry; - + } finally { releasePayload(response); } } - + String parsePayloadOrNull(HttpResponse response) { if (response.getPayload() != null) { try { diff --git a/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java b/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java index 0aa578f3e4..c59629cfd2 100644 --- a/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java +++ b/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java @@ -18,13 +18,14 @@ */ package org.jclouds.openstack.handlers; +import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.classextension.EasyMock.createMock; -import static org.easymock.classextension.EasyMock.replay; -import static org.easymock.classextension.EasyMock.verify; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; import static org.testng.Assert.assertTrue; +import org.jclouds.domain.Credentials; import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; @@ -47,23 +48,23 @@ public class RetryOnRenewTest { HttpRequest request = createMock(HttpRequest.class); HttpResponse response = createMock(HttpResponse.class); @SuppressWarnings("unchecked") - LoadingCache cache = createMock(LoadingCache.class); + LoadingCache cache = createMock(LoadingCache.class); expect(command.getCurrentRequest()).andReturn(request); cache.invalidateAll(); expectLastCall(); - + expect(response.getPayload()).andReturn(Payloads.newStringPayload("token expired, please renew")).anyTimes(); expect(response.getStatusCode()).andReturn(401).atLeastOnce(); replay(command); replay(response); replay(cache); - + RetryOnRenew retry = new RetryOnRenew(); retry.authenticationResponseCache = cache; - + assertTrue(retry.shouldRetryRequest(command, response)); verify(command); diff --git a/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunction.java b/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunction.java new file mode 100644 index 0000000000..c2fd9f9c5b --- /dev/null +++ b/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunction.java @@ -0,0 +1,77 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.concurrent; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; + +import java.util.concurrent.TimeoutException; + +import org.jclouds.util.Throwables2; + +import com.google.common.base.Function; +import com.google.common.collect.ForwardingObject; + +/** + * + * @author Adrian Cole + */ +public class RetryOnTimeOutExceptionFunction extends ForwardingObject implements Function{ + private final Function delegate; + + public RetryOnTimeOutExceptionFunction(Function delegate) { + this.delegate = checkNotNull(delegate, "delegate"); + } + + //TODO: backoff limited retry handler + @Override + public V apply(K key) { + TimeoutException ex = null; + for (int i = 0; i < 3; i++) { + try { + ex = null; + return delegate().apply(key); + } catch (Exception e) { + if ((ex = Throwables2.getFirstThrowableOfType(e, TimeoutException.class)) != null) + continue; + throw propagate(e); + } + } + if (ex != null) + throw propagate(ex); + assert false; + return null; + } + + @Override + public boolean equals(Object obj) { + return delegate.equals(obj); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + protected Function delegate() { + return delegate; + } + +} \ No newline at end of file diff --git a/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunctionTest.java b/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunctionTest.java new file mode 100644 index 0000000000..4b2136e3a1 --- /dev/null +++ b/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionFunctionTest.java @@ -0,0 +1,126 @@ +/** + * 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.concurrent; + +import static org.easymock.EasyMock.expect; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; +import static org.testng.Assert.assertEquals; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeoutException; + +import org.jclouds.rest.AuthorizationException; +import org.testng.annotations.Test; + +import com.google.common.base.Function; + +/** + * Tests behavior of RetryOnTimeOutExceptionFunction + * + * @author Adrian Cole + */ +@Test(groups = "unit", singleThreaded = true, testName = "RetryOnTimeOutExceptionFunctionTest") +public class RetryOnTimeOutExceptionFunctionTest { + ExecutorService executorService = MoreExecutors.sameThreadExecutor(); + + @SuppressWarnings("unchecked") + @Test + public void testGetThrowsOriginalExceptionButRetriesOnTimeoutException() throws InterruptedException, ExecutionException { + Function delegate = createMock(Function.class); + TimeoutException timeout = createMock(TimeoutException.class); + RuntimeException throwable = new RuntimeException(timeout); + + expect(delegate.apply("baz")).andThrow(throwable); + expect(timeout.getCause()).andReturn(null).anyTimes(); + expect(delegate.apply("baz")).andThrow(throwable); + expect(delegate.apply("baz")).andThrow(throwable); + + replay(delegate); + replay(timeout); + + RetryOnTimeOutExceptionFunction supplier = new RetryOnTimeOutExceptionFunction( + delegate); + try { + supplier.apply("baz"); + assert false; + } catch (RuntimeException e) { + assertEquals(e.getCause(), timeout); + } + + verify(delegate); + verify(timeout); + + } + + @SuppressWarnings("unchecked") + @Test + public void testGetAllowsTwoFailuresOnTimeoutException() throws InterruptedException, ExecutionException { + Function delegate = createMock(Function.class); + TimeoutException timeout = createMock(TimeoutException.class); + RuntimeException throwable = new RuntimeException(timeout); + + expect(delegate.apply("baz")).andThrow(throwable); + expect(timeout.getCause()).andReturn(null).anyTimes(); + expect(delegate.apply("baz")).andThrow(throwable); + expect(delegate.apply("baz")).andReturn("foo"); + + replay(delegate); + replay(timeout); + + RetryOnTimeOutExceptionFunction supplier = new RetryOnTimeOutExceptionFunction( + delegate); + assertEquals(supplier.apply("baz"), "foo"); + + verify(delegate); + verify(timeout); + } + + @SuppressWarnings("unchecked") + @Test + public void testGetAllowsNoFailuresOnOtherExceptions() throws InterruptedException, ExecutionException { + Function delegate = createMock(Function.class); + AuthorizationException auth = createMock(AuthorizationException.class); + RuntimeException throwable = new RuntimeException(auth); + + expect(delegate.apply("baz")).andThrow(throwable); + expect(auth.getCause()).andReturn(null).anyTimes(); + + + replay(delegate); + replay(auth); + + RetryOnTimeOutExceptionFunction supplier = new RetryOnTimeOutExceptionFunction( + delegate); + + try { + supplier.apply("baz"); + assert false; + } catch (RuntimeException e) { + assertEquals(e.getCause(), auth); + } + + verify(delegate); + verify(auth); + + } + +} From a14ad27258b56857de74b7ed199e1263786449f1 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 11:43:08 -0800 Subject: [PATCH 69/82] Issue 731: code cleanup --- .../config/OpenStackAuthenticationModule.java | 29 +++++++++---------- .../openstack/handlers/RetryOnRenew.java | 26 ++++++----------- .../openstack/handlers/RetryOnRenewTest.java | 3 +- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java b/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java index 0d260b205b..d2c8949c26 100644 --- a/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java +++ b/common/openstack/src/main/java/org/jclouds/openstack/config/OpenStackAuthenticationModule.java @@ -18,6 +18,9 @@ */ package org.jclouds.openstack.config; +import static com.google.common.base.Suppliers.memoizeWithExpiration; +import static com.google.common.base.Throwables.propagate; + import java.util.Date; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -41,12 +44,9 @@ import org.jclouds.rest.AsyncClientFactory; import com.google.common.base.Function; import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; -import com.google.common.base.Throwables; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import com.google.common.util.concurrent.UncheckedExecutionException; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -102,9 +102,14 @@ public class OpenStackAuthenticationModule extends AbstractModule { .authenticate(input.identity, input.credential); return response.get(30, TimeUnit.SECONDS); } catch (Exception e) { - throw Throwables.propagate(e); + throw propagate(e); } } + + @Override + public String toString() { + return "authenticate()"; + } }); } @@ -113,13 +118,9 @@ public class OpenStackAuthenticationModule extends AbstractModule { @Provides @Singleton public LoadingCache provideAuthenticationResponseCache2( - final Function getAuthenticationResponse, - @Provider final Credentials creds) { - - LoadingCache cache = CacheBuilder.newBuilder().expireAfterWrite(23, - TimeUnit.HOURS).build(CacheLoader.from(getAuthenticationResponse)); - - return cache; + Function getAuthenticationResponse) { + return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS).build( + CacheLoader.from(getAuthenticationResponse)); } @Provides @@ -131,10 +132,8 @@ public class OpenStackAuthenticationModule extends AbstractModule { public AuthenticationResponse get() { try { return cache.get(creds); - } catch (UncheckedExecutionException e) { - throw Throwables.propagate(e.getCause()); } catch (ExecutionException e) { - throw Throwables.propagate(e.getCause()); + throw propagate(e.getCause()); } } }; @@ -144,7 +143,7 @@ public class OpenStackAuthenticationModule extends AbstractModule { @Singleton @TimeStamp protected Supplier provideCacheBusterDate() { - return Suppliers.memoizeWithExpiration(new Supplier() { + return memoizeWithExpiration(new Supplier() { public Date get() { return new Date(); } diff --git a/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java b/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java index dc0cb7e6da..87d073979d 100644 --- a/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java +++ b/common/openstack/src/main/java/org/jclouds/openstack/handlers/RetryOnRenew.java @@ -18,10 +18,9 @@ */ package org.jclouds.openstack.handlers; +import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; import static org.jclouds.http.HttpUtils.releasePayload; -import java.io.IOException; - import javax.annotation.Resource; import org.jclouds.domain.Credentials; @@ -31,7 +30,6 @@ import org.jclouds.http.HttpRetryHandler; import org.jclouds.logging.Logger; import org.jclouds.openstack.OpenStackAuthAsyncClient.AuthenticationResponse; import org.jclouds.openstack.reference.AuthHeaders; -import org.jclouds.util.Strings2; import com.google.common.cache.LoadingCache; import com.google.common.collect.Multimap; @@ -49,8 +47,12 @@ public class RetryOnRenew implements HttpRetryHandler { @Resource protected Logger logger = Logger.NULL; + private final LoadingCache authenticationResponseCache; + @Inject - LoadingCache authenticationResponseCache; + protected RetryOnRenew(LoadingCache authenticationResponseCache) { + this.authenticationResponseCache = authenticationResponseCache; + } @Override public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) { @@ -64,9 +66,9 @@ public class RetryOnRenew implements HttpRetryHandler { && headers.containsKey(AuthHeaders.AUTH_KEY) && !headers.containsKey(AuthHeaders.AUTH_TOKEN)) { retry = false; } else { - String content = parsePayloadOrNull(response); - if (content != null && content.contains("lease renew")) { - // Otherwise invalidate the token cache, to force reauthentication + byte[] content = closeClientButKeepContentStream(response); + if (content != null && new String(content).contains("lease renew")) { + logger.debug("invalidating authentication token"); authenticationResponseCache.invalidateAll(); retry = true; } else { @@ -82,14 +84,4 @@ public class RetryOnRenew implements HttpRetryHandler { } } - String parsePayloadOrNull(HttpResponse response) { - if (response.getPayload() != null) { - try { - return Strings2.toStringAndClose(response.getPayload().getInput()); - } catch (IOException e) { - logger.warn(e, "exception reading error from response", response); - } - } - return null; - } } diff --git a/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java b/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java index c59629cfd2..36a6c3a7d4 100644 --- a/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java +++ b/common/openstack/src/test/java/org/jclouds/openstack/handlers/RetryOnRenewTest.java @@ -62,8 +62,7 @@ public class RetryOnRenewTest { replay(response); replay(cache); - RetryOnRenew retry = new RetryOnRenew(); - retry.authenticationResponseCache = cache; + RetryOnRenew retry = new RetryOnRenew(cache); assertTrue(retry.shouldRetryRequest(command, response)); From 88400f64415cfcdca340bece74004b28aef27dd5 Mon Sep 17 00:00:00 2001 From: andreisavu Date: Sun, 15 Jan 2012 20:06:02 +0200 Subject: [PATCH 70/82] Add TemplateOptions to create SSD Drives on CloudSigma providers --- .../CloudSigmaComputeServiceAdapter.java | 16 +- .../CloudSigmaTemplateBuilderImpl.java | 46 +++ ...CloudSigmaComputeServiceContextModule.java | 11 + .../functions/ServerInfoToNodeMetadata.java | 5 +- .../options/CloudSigmaTemplateOptions.java | 349 ++++++++++++++++++ ...loudSigmaZurichComputeServiceLiveTest.java | 48 +++ 6 files changed, 468 insertions(+), 7 deletions(-) create mode 100644 apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaTemplateBuilderImpl.java create mode 100644 apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/options/CloudSigmaTemplateOptions.java diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java index d67a7986be..6886561e46 100644 --- a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java +++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceAdapter.java @@ -32,6 +32,8 @@ import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.cloudsigma.CloudSigmaClient; +import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions; +import org.jclouds.cloudsigma.domain.AffinityType; import org.jclouds.cloudsigma.domain.Device; import org.jclouds.cloudsigma.domain.DriveInfo; import org.jclouds.cloudsigma.domain.DriveType; @@ -69,7 +71,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException; /** * defines the connection between the {@link CloudSigmaClient} implementation * and the jclouds {@link ComputeService} - * + * */ @Singleton public class CloudSigmaComputeServiceAdapter implements @@ -109,9 +111,15 @@ public class CloudSigmaComputeServiceAdapter implements @Override public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String tag, String name, Template template) { long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l); - logger.debug(">> imaging boot drive source(%s) bytes(%d)", template.getImage().getId(), bootSize); + AffinityType affinityType = AffinityType.HDD; + if (template.getOptions() instanceof CloudSigmaTemplateOptions) { + CloudSigmaTemplateOptions options = CloudSigmaTemplateOptions.class.cast(template.getOptions()); + affinityType = options.getDiskDriveAffinity(); + } + logger.debug(">> imaging boot drive source(%s) bytes(%d) affinityType(%s)", + template.getImage().getId(), bootSize, affinityType); DriveInfo drive = client.cloneDrive(template.getImage().getId(), template.getImage().getId(), - new CloneDriveOptions().size(bootSize)); + new CloneDriveOptions().size(bootSize).affinity(affinityType)); boolean success = driveNotClaimed.apply(drive); logger.debug("<< image(%s) complete(%s)", drive.getUuid(), success); if (!success) { @@ -152,7 +160,7 @@ public class CloudSigmaComputeServiceAdapter implements } }).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu))) - .volumes(ImmutableList. of(new VolumeImpl(size, true, true))).build()); + .volumes(ImmutableList.of(new VolumeImpl(size, true, true))).build()); } return hardware.build(); } diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaTemplateBuilderImpl.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaTemplateBuilderImpl.java new file mode 100644 index 0000000000..57a31f2d05 --- /dev/null +++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/CloudSigmaTemplateBuilderImpl.java @@ -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.cloudsigma.compute; + +import com.google.common.base.Supplier; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.domain.internal.TemplateBuilderImpl; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.domain.Location; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import java.util.Set; + +/** + * @author Andrei Savu + */ +public class CloudSigmaTemplateBuilderImpl extends TemplateBuilderImpl { + @Inject + public CloudSigmaTemplateBuilderImpl(@Memoized Supplier> locations, + @Memoized Supplier> images, @Memoized Supplier> hardwares, + Supplier defaultLocation2, @Named("DEFAULT") Provider optionsProvider, + @Named("DEFAULT") Provider defaultTemplateProvider) { + super(locations, images, hardwares, defaultLocation2, optionsProvider, defaultTemplateProvider); + } +} diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java index 730ec4f3a3..29d62af92b 100644 --- a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java +++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/config/CloudSigmaComputeServiceContextModule.java @@ -26,12 +26,14 @@ import javax.inject.Singleton; import org.jclouds.cloudsigma.CloudSigmaAsyncClient; import org.jclouds.cloudsigma.CloudSigmaClient; import org.jclouds.cloudsigma.compute.CloudSigmaComputeServiceAdapter; +import org.jclouds.cloudsigma.compute.CloudSigmaTemplateBuilderImpl; import org.jclouds.cloudsigma.compute.functions.ParseOsFamilyVersion64BitFromImageName; import org.jclouds.cloudsigma.compute.functions.PreinstalledDiskToImage; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.DeviceToVolume; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.FindImageForId; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.GetImageIdFromServer; +import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions; import org.jclouds.cloudsigma.domain.Device; import org.jclouds.cloudsigma.domain.DriveInfo; import org.jclouds.cloudsigma.domain.Server; @@ -46,6 +48,7 @@ import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamilyVersion64Bit; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.Volume; +import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; import org.jclouds.functions.IdentityFunction; @@ -104,6 +107,8 @@ public class CloudSigmaComputeServiceContextModule }).to(ParseOsFamilyVersion64BitFromImageName.class); bind(new TypeLiteral>() { }).to(OnlyLocationOrFirstZone.class); + bind(TemplateBuilder.class) + .to(CloudSigmaTemplateBuilderImpl.class); } @Provides @@ -134,4 +139,10 @@ public class CloudSigmaComputeServiceContextModule return new RetryablePredicate(Predicates.not(driveClaimed), timeouts.nodeRunning, 1000, TimeUnit.MILLISECONDS); } + + @Provides + @Singleton + protected TemplateOptions templateOptions() { + return new CloudSigmaTemplateOptions(); + } } \ No newline at end of file diff --git a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java index 4c433c92c4..7e6bfc88dd 100644 --- a/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java +++ b/apis/cloudsigma/src/main/java/org/jclouds/cloudsigma/compute/functions/ServerInfoToNodeMetadata.java @@ -21,7 +21,6 @@ package org.jclouds.cloudsigma.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName; -import java.util.List; import java.util.Map; import java.util.Set; @@ -102,7 +101,7 @@ public class ServerInfoToNodeMetadata implements Function of(from.getVnc().getIp())); builder.privateAddresses(ImmutableSet. of()); @@ -133,7 +132,7 @@ public class ServerInfoToNodeMetadata implements Function userMetadata) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return CloudSigmaTemplateOptions.class.cast(options.userMetadata(userMetadata)); + } + + @Deprecated + public static CloudSigmaTemplateOptions overrideLoginUserWith(String user) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideLoginUserWith(user); + } + + public static CloudSigmaTemplateOptions overrideLoginUser(String user) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideLoginUser(user); + } + + public static CloudSigmaTemplateOptions overrideLoginPassword(String password) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideLoginPassword(password); + } + + public static CloudSigmaTemplateOptions overrideLoginPrivateKey(String privateKey) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideLoginPrivateKey(privateKey); + } + + public static CloudSigmaTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideAuthenticateSudo(authenticateSudo); + } + + @Deprecated + public static CloudSigmaTemplateOptions overrideLoginCredentialWith(String credential) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideLoginCredentialWith(credential); + } + + @Deprecated + public static CloudSigmaTemplateOptions overrideCredentialsWith(Credentials credentials) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideCredentialsWith(credentials); + } + + public static CloudSigmaTemplateOptions overrideLoginCredentials(LoginCredentials credentials) { + CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions(); + return options.overrideLoginCredentials(credentials); + } + } + + // methods that only facilitate returning the correct object type + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions blockOnPort(int port, int seconds) { + return CloudSigmaTemplateOptions.class.cast(super.blockOnPort(port, seconds)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions inboundPorts(int... ports) { + return CloudSigmaTemplateOptions.class.cast(super.inboundPorts(ports)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions authorizePublicKey(String publicKey) { + return CloudSigmaTemplateOptions.class.cast(super.authorizePublicKey(publicKey)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions installPrivateKey(String privateKey) { + return CloudSigmaTemplateOptions.class.cast(super.installPrivateKey(privateKey)); + } + + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public CloudSigmaTemplateOptions runScript(Payload script) { + return CloudSigmaTemplateOptions.class.cast(super.runScript(script)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions blockUntilRunning(boolean blockUntilRunning) { + return CloudSigmaTemplateOptions.class.cast(super.blockUntilRunning(blockUntilRunning)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions dontAuthorizePublicKey() { + return CloudSigmaTemplateOptions.class.cast(super.dontAuthorizePublicKey()); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions nameTask(String name) { + return CloudSigmaTemplateOptions.class.cast(super.nameTask(name)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions runAsRoot(boolean runAsRoot) { + return CloudSigmaTemplateOptions.class.cast(super.runAsRoot(runAsRoot)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions runScript(Statement script) { + return CloudSigmaTemplateOptions.class.cast(super.runScript(script)); + } + + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public CloudSigmaTemplateOptions overrideCredentialsWith(Credentials overridingCredentials) { + return CloudSigmaTemplateOptions.class.cast(super.overrideCredentialsWith(overridingCredentials)); + } + + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public CloudSigmaTemplateOptions overrideLoginUserWith(String loginUser) { + return CloudSigmaTemplateOptions.class.cast(super.overrideLoginUserWith(loginUser)); + } + + /** + * {@inheritDoc} + */ + @Deprecated + @Override + public CloudSigmaTemplateOptions overrideLoginCredentialWith(String loginCredential) { + return CloudSigmaTemplateOptions.class.cast(super.overrideLoginCredentialWith(loginCredential)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions overrideLoginCredentials(LoginCredentials overridingCredentials) { + return CloudSigmaTemplateOptions.class.cast(super.overrideLoginCredentials(overridingCredentials)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions overrideLoginPassword(String password) { + return CloudSigmaTemplateOptions.class.cast(super.overrideLoginPassword(password)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions overrideLoginPrivateKey(String privateKey) { + return CloudSigmaTemplateOptions.class.cast(super.overrideLoginPrivateKey(privateKey)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions overrideLoginUser(String loginUser) { + return CloudSigmaTemplateOptions.class.cast(super.overrideLoginUser(loginUser)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) { + return CloudSigmaTemplateOptions.class.cast(super.overrideAuthenticateSudo(authenticateSudo)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions userMetadata(Map userMetadata) { + return CloudSigmaTemplateOptions.class.cast(super.userMetadata(userMetadata)); + } + + /** + * {@inheritDoc} + */ + @Override + public CloudSigmaTemplateOptions userMetadata(String key, String value) { + return CloudSigmaTemplateOptions.class.cast(super.userMetadata(key, value)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + CloudSigmaTemplateOptions that = (CloudSigmaTemplateOptions) o; + + if (diskDriveAffinity != that.diskDriveAffinity) return false; + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (diskDriveAffinity != null ? diskDriveAffinity.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "CloudSigmaTemplateOptions{" + + "diskDriveAffinity=" + diskDriveAffinity + + '}'; + } +} diff --git a/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java b/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java index 02213e0ac3..fd25db453e 100644 --- a/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java +++ b/providers/cloudsigma-zrh/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaZurichComputeServiceLiveTest.java @@ -18,8 +18,26 @@ */ package org.jclouds.cloudsigma.compute; +import org.jclouds.cloudsigma.CloudSigmaClient; +import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions; +import org.jclouds.cloudsigma.domain.AffinityType; +import org.jclouds.cloudsigma.domain.Device; +import org.jclouds.cloudsigma.domain.DriveInfo; +import org.jclouds.cloudsigma.domain.ServerInfo; +import org.jclouds.compute.RunNodesException; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.domain.TemplateBuilder; import org.testng.annotations.Test; +import java.util.Set; + +import static com.google.common.collect.Iterables.contains; +import static com.google.common.collect.Iterables.get; +import static org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions.Builder.diskDriveAffinity; +import static org.jclouds.compute.predicates.NodePredicates.inGroup; +import static org.testng.Assert.assertTrue; + /** * * @author Adrian Cole @@ -31,4 +49,34 @@ public class CloudSigmaZurichComputeServiceLiveTest extends CloudSigmaComputeSer provider = "cloudsigma-zrh"; } + @Test + public void testStartNodeWithSSD() throws RunNodesException { + String group = this.group + "-ssd"; + + TemplateBuilder builder = client.templateBuilder(); + assert builder instanceof CloudSigmaTemplateBuilderImpl; + + Template template = builder.options(diskDriveAffinity(AffinityType.SSD)).build(); + assert template.getOptions() instanceof CloudSigmaTemplateOptions; + + try { + Set nodes = client.createNodesInGroup(group, 1, template); + NodeMetadata node = get(nodes, 0); + + CloudSigmaClient api = CloudSigmaClient.class.cast(client.getContext() + .getProviderSpecificContext().getApi()); + + // Note: I wanted to use node.getHardware().getVolumes() but there is no + // way to go from a Volume to a DriveInfo + + ServerInfo serverInfo = api.getServerInfo(node.getId()); + Device rootDevice = get(serverInfo.getDevices().values(), 0); + DriveInfo driveInfo = api.getDriveInfo(rootDevice.getDriveUuid()); + assertTrue(contains(driveInfo.getTags(), "affinity:ssd")); + + } finally { + client.destroyNodesMatching(inGroup(group)); + } + } + } From 2dfdbb4b56112fe0147d805d7f4a0fa4e4d4d4fb Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 14:31:05 -0800 Subject: [PATCH 71/82] fixed url for blobstore copy and improved code --- .../internal/BaseBlobLiveTest.java | 29 +++++++++---------- project/pom.xml | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java index 0055e50277..7bd700ae84 100644 --- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java +++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobLiveTest.java @@ -21,12 +21,12 @@ package org.jclouds.blobstore.integration.internal; import static com.google.common.base.Preconditions.checkNotNull; import static org.testng.Assert.assertEquals; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; +import java.net.URI; import org.jclouds.blobstore.domain.Blob; import org.jclouds.crypto.CryptoStreams; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; @@ -42,25 +42,24 @@ import org.testng.annotations.Test; public class BaseBlobLiveTest extends BaseBlobStoreIntegrationTest { private static final String sysHttpStreamUrl = System.getProperty("jclouds.blobstore.httpstream.url"); - private static final String sysHttpStreamETag = System.getProperty("jclouds.blobstore.httpstream.md5"); + private static final String sysHttpStreamMD5 = System.getProperty("jclouds.blobstore.httpstream.md5"); @Test - @Parameters({ "jclouds.blobstore.httpstream.url", "jclouds.blobstore.httpstream.md5" }) - public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamETag) throws Exception { + @Parameters( { "jclouds.blobstore.httpstream.url", "jclouds.blobstore.httpstream.md5" }) + public void testCopyUrl(@Optional String httpStreamUrl, @Optional String httpStreamMD5) throws Exception { httpStreamUrl = checkNotNull(httpStreamUrl != null ? httpStreamUrl : sysHttpStreamUrl, "httpStreamUrl"); - httpStreamETag = checkNotNull(httpStreamETag != null ? httpStreamETag : sysHttpStreamETag, "httpStreamMd5"); + httpStreamMD5 = checkNotNull(httpStreamMD5 != null ? httpStreamMD5 : sysHttpStreamMD5, "httpStreamMd5"); + + HttpResponse response = context.utils().http().invoke( + HttpRequest.builder().method("GET").endpoint(URI.create(httpStreamUrl)).build()); + long length = response.getPayload().getContentMetadata().getContentLength(); String name = "hello"; + byte[] md5 = CryptoStreams.hex(httpStreamMD5); - URL url = new URL(httpStreamUrl); - byte[] md5 = CryptoStreams.hex(httpStreamETag); - - URLConnection connection = url.openConnection(); - long length = connection.getContentLength(); - InputStream input = connection.getInputStream(); - - Blob blob = context.getBlobStore().blobBuilder(name).payload(input).contentLength(length).contentMD5(md5).build(); + Blob blob = context.getBlobStore().blobBuilder(name).payload(response.getPayload()).contentLength(length) + .contentMD5(md5).build(); String container = getContainerName(); try { context.getBlobStore().putBlob(container, blob); diff --git a/project/pom.xml b/project/pom.xml index 80c8027cd3..467a5fe012 100644 --- a/project/pom.xml +++ b/project/pom.xml @@ -194,7 +194,7 @@ gitsite:git@github.com/jclouds/jclouds-maven-site.git - http://apache.opensourceresources.org//commons/logging/binaries/commons-logging-1.1.1-bin.tar.gz + http://apache.deathculture.net//commons/logging/binaries/commons-logging-1.1.1-bin.tar.gz e5de09672af9b386c30a311654d8541a ${jclouds.wire.httpstream.url} ${jclouds.wire.httpstream.md5} From 82e44d952b5b1b7d55f70db2a93ce4b81a8ff0c3 Mon Sep 17 00:00:00 2001 From: Mattias Holmqvist Date: Tue, 10 Jan 2012 07:31:22 +0100 Subject: [PATCH 72/82] VirtualBox: Removed private propagate-methods and use Google directly instead. Minor code cleanup. --- .../AttachNATAdapterToMachineIfNotAlreadyExists.java | 2 +- .../functions/RetrieveActiveBridgedInterfaces.java | 12 ++++-------- .../functions/TakeSnapshotIfNotAlreadyAttached.java | 9 ++------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java index 8aced464b3..10d8f0b208 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/AttachNATAdapterToMachineIfNotAlreadyExists.java @@ -55,7 +55,7 @@ public class AttachNATAdapterToMachineIfNotAlreadyExists implements Function T propagate(Exception e) { - Throwables.propagate(e); - assert false; - return null; - } - private class IsActiveBridgedInterface implements Predicate { private NetworkInterface networkInterface; @@ -130,7 +125,8 @@ public class RetrieveActiveBridgedInterfaces implements Function T propogate(Exception e) { - Throwables.propagate(e); - assert false; - return null; - } } From f1427fbb7401ec8a5f8a045708ec120d75ec6fbd Mon Sep 17 00:00:00 2001 From: Mattias Holmqvist Date: Tue, 10 Jan 2012 07:34:00 +0100 Subject: [PATCH 73/82] Moved statements to separate package --- .../{domain => statements}/GetIPAddressFromMAC.java | 3 ++- .../{domain => statements}/InstallGuestAdditions.java | 3 ++- .../{domain => statements}/ScanNetworkWithPing.java | 4 ++-- .../jclouds/virtualbox/{domain => statements}/Statements.java | 2 +- .../virtualbox/domain/ExportIpAddressForVMNamedTest.java | 2 +- .../jclouds/virtualbox/domain/InstallGuestAdditionsTest.java | 1 + .../jclouds/virtualbox/domain/ScanNetworkWithPingTest.java | 1 + 7 files changed, 10 insertions(+), 6 deletions(-) rename sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/{domain => statements}/GetIPAddressFromMAC.java (98%) rename sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/{domain => statements}/InstallGuestAdditions.java (98%) rename sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/{domain => statements}/ScanNetworkWithPing.java (97%) rename sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/{domain => statements}/Statements.java (97%) diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/GetIPAddressFromMAC.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/GetIPAddressFromMAC.java similarity index 98% rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/GetIPAddressFromMAC.java rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/GetIPAddressFromMAC.java index 19e5bb7cb7..5bea1808f2 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/GetIPAddressFromMAC.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/GetIPAddressFromMAC.java @@ -16,7 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtualbox.domain; + +package org.jclouds.virtualbox.statements; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/InstallGuestAdditions.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java similarity index 98% rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/InstallGuestAdditions.java rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java index 68ccedc10b..b0eb11a425 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/InstallGuestAdditions.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java @@ -16,7 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtualbox.domain; + +package org.jclouds.virtualbox.statements; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.scriptbuilder.domain.Statements.call; diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ScanNetworkWithPing.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/ScanNetworkWithPing.java similarity index 97% rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ScanNetworkWithPing.java rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/ScanNetworkWithPing.java index ad9f6def20..1a35434e57 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ScanNetworkWithPing.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/ScanNetworkWithPing.java @@ -1,4 +1,4 @@ -/** +/* * Licensed to jclouds, Inc. (jclouds) under one or more * contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -17,7 +17,7 @@ * under the License. */ -package org.jclouds.virtualbox.domain; +package org.jclouds.virtualbox.statements; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Statements.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java similarity index 97% rename from sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Statements.java rename to sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java index 944975afd0..23ea1dc59c 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Statements.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/statements/Statements.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.virtualbox.domain; +package org.jclouds.virtualbox.statements; import org.jclouds.scriptbuilder.domain.AppendFile; import org.jclouds.scriptbuilder.domain.Call; diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java index 47a9115691..33843e9c13 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ExportIpAddressForVMNamedTest.java @@ -19,7 +19,7 @@ package org.jclouds.virtualbox.domain; import static org.jclouds.scriptbuilder.domain.Statements.interpret; -import static org.jclouds.virtualbox.domain.Statements.exportIpAddressFromVmNamed; +import static org.jclouds.virtualbox.statements.Statements.exportIpAddressFromVmNamed; import static org.testng.Assert.assertEquals; import java.io.IOException; diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java index 675e2db794..8aace24860 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java @@ -24,6 +24,7 @@ import java.io.IOException; import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.ShellToken; +import org.jclouds.virtualbox.statements.InstallGuestAdditions; import org.testng.annotations.Test; import com.google.common.base.Charsets; diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java index f3801b0d22..02a352f0a2 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/ScanNetworkWithPingTest.java @@ -21,6 +21,7 @@ package org.jclouds.virtualbox.domain; import static org.testng.Assert.assertEquals; import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.virtualbox.statements.ScanNetworkWithPing; import org.testng.annotations.Test; /** From ef0b6891131ab03e13c5b1fcd2f0ef9c927cb3b2 Mon Sep 17 00:00:00 2001 From: Mattias Holmqvist Date: Sun, 15 Jan 2012 23:41:11 +0100 Subject: [PATCH 74/82] First step on IsoSpec/NetworkSpec/IMachineSpec. Also reverted ubuntu version to 11.04. --- .../VirtualBoxPropertiesBuilder.java | 3 +- .../virtualbox/domain/IMachineSpec.java | 113 +++++++++++++++++ .../jclouds/virtualbox/domain/IsoSpec.java | 116 ++++++++++++++++++ .../virtualbox/domain/NetworkSpec.java | 87 +++++++++++++ .../org/jclouds/virtualbox/domain/VmSpec.java | 45 ++----- .../functions/CreateAndInstallVm.java | 104 +++++++--------- ...isterMachineFromIsoIfNotAlreadyExists.java | 24 ++-- .../jclouds/virtualbox/domain/VmSpecTest.java | 3 - ...hineFromIsoIfNotAlreadyExistsLiveTest.java | 44 ++++--- .../functions/CreateAndInstallVmLiveTest.java | 59 +++++---- ...hineFromIsoIfNotAlreadyExistsLiveTest.java | 62 +++++++--- ...rMachineFromIsoIfNotAlreadyExistsTest.java | 60 ++++++--- ...rMachineIfExistsAndDeleteItsMediaTest.java | 8 +- .../predicates/IsLinkedClonesLiveTest.java | 23 ++-- 14 files changed, 545 insertions(+), 206 deletions(-) create mode 100644 sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IMachineSpec.java create mode 100644 sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IsoSpec.java create mode 100644 sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NetworkSpec.java diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java index 7b2014b818..2225281d11 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxPropertiesBuilder.java @@ -64,7 +64,8 @@ public class VirtualBoxPropertiesBuilder extends PropertiesBuilder { properties.put(VIRTUALBOX_ISO_URL, "http://releases.ubuntu.com/11.04/ubuntu-11.04-server-i386.iso"); properties.put(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE, " " + "/install/vmlinuz noapic preseed/url=PRECONFIGURATION_URL " - + "debian-installer=en_US auto locale=en_US kbd-chooser/method=us " + "hostname=" + "HOSTNAME " + + "debian-installer=en_US auto locale=en_US kbd-chooser/method=us " + + "hostname=" + "HOSTNAME " + "fb=false debconf/frontend=noninteractive " + "keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false " + "initrd=/install/initrd.gz -- "); diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IMachineSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IMachineSpec.java new file mode 100644 index 0000000000..b753d49b7b --- /dev/null +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IMachineSpec.java @@ -0,0 +1,113 @@ +/* + * 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.virtualbox.domain; + +import com.google.common.base.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A complete specification of a "master" node, including the ISO, networking setup + * and the physical machine specification. + */ +public class IMachineSpec { + + private VmSpec vmSpec; + private IsoSpec isoSpec; + private NetworkSpec networkSpec; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private VmSpec vmSpec; + private IsoSpec isoSpec; + private NetworkSpec networkSpec; + + public Builder vm(VmSpec vmSpec) { + this.vmSpec = vmSpec; + return this; + } + + public Builder network(NetworkSpec networkSpec) { + this.networkSpec = networkSpec; + return this; + } + + public Builder iso(IsoSpec isoSpec) { + this.isoSpec = isoSpec; + return this; + } + + public IMachineSpec build() { + return new IMachineSpec(vmSpec, isoSpec, networkSpec); + } + + } + + public IMachineSpec(VmSpec vmSpec, IsoSpec isoSpec, NetworkSpec networkSpec) { + checkNotNull(vmSpec, "vmSpec"); + checkNotNull(isoSpec, "isoSpec"); + checkNotNull(networkSpec, "networkSpec"); + this.vmSpec = vmSpec; + this.isoSpec = isoSpec; + this.networkSpec = networkSpec; + } + + public VmSpec getVmSpec() { + return vmSpec; + } + + public IsoSpec getIsoSpec() { + return isoSpec; + } + + public NetworkSpec getNetworkSpec() { + return networkSpec; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof VmSpec) { + IMachineSpec other = (IMachineSpec) o; + return Objects.equal(vmSpec, other.vmSpec) && + Objects.equal(isoSpec, other.isoSpec) && + Objects.equal(networkSpec, other.networkSpec); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(vmSpec,isoSpec,networkSpec); + } + + @Override + public String toString() { + return "IMachineSpec{" + + "vmSpec=" + vmSpec + + ", isoSpec=" + isoSpec + + ", networkSpec=" + networkSpec + + '}'; + } +} diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IsoSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IsoSpec.java new file mode 100644 index 0000000000..2b0bc46293 --- /dev/null +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/IsoSpec.java @@ -0,0 +1,116 @@ +/* + * 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.virtualbox.domain; + +import com.google.common.base.Objects; +import com.google.common.base.Supplier; +import org.jclouds.virtualbox.Preconfiguration; + +import java.net.URI; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The information needed to create a machine from a .iso file. + */ +public class IsoSpec { + + private final String installationKeySequence; + private final String sourcePath; + private final Supplier preConfigurationUri; + + public IsoSpec(String sourcePath, String installationKeySequence, @Preconfiguration Supplier preConfigurationUri) { + checkNotNull(sourcePath, "sourcePath"); + checkNotNull(installationKeySequence, "installationKeySequence"); + checkNotNull(preConfigurationUri, "preConfigurationUri"); + this.sourcePath = sourcePath; + this.installationKeySequence = installationKeySequence; + this.preConfigurationUri = preConfigurationUri; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String installationSequence; + private Supplier preConfigurationUri; + private String sourcePath; + + public Builder installationScript(String installationSequence) { + this.installationSequence = installationSequence; + return this; + } + + public Builder preConfiguration(Supplier preConfigurationUri) { + this.preConfigurationUri = preConfigurationUri; + return this; + } + + public Builder sourcePath(String sourcePath) { + this.sourcePath = sourcePath; + return this; + } + + + public IsoSpec build() { + return new IsoSpec(sourcePath, installationSequence, preConfigurationUri); + } + } + + public String getInstallationKeySequence() { + return installationKeySequence; + } + + public Supplier getPreConfigurationUri() { + return preConfigurationUri; + } + + public String getSourcePath() { + return sourcePath; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof VmSpec) { + IsoSpec other = (IsoSpec) o; + return Objects.equal(sourcePath, other.sourcePath) && + Objects.equal(installationKeySequence, other.installationKeySequence) && + Objects.equal(preConfigurationUri, other.preConfigurationUri); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(sourcePath, installationKeySequence, preConfigurationUri); + } + + @Override + public String toString() { + return "IsoSpec{" + + "sourcePath='" + sourcePath + '\'' + + "installationKeySequence='" + installationKeySequence + '\'' + + ", preConfigurationUri=" + preConfigurationUri + + '}'; + } +} diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NetworkSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NetworkSpec.java new file mode 100644 index 0000000000..72bb8e5dcb --- /dev/null +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NetworkSpec.java @@ -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.virtualbox.domain; + +import com.google.common.base.Objects; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Describes the network configuration for a VirtualBox machine. + */ +public class NetworkSpec { + + private final Map natNetworkAdapters; + + public NetworkSpec(final Map natNetworkAdapters) { + checkNotNull(natNetworkAdapters, "natNetworkAdapters"); + this.natNetworkAdapters = natNetworkAdapters; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private Map natNetworkAdapters = new HashMap(); + + public Builder natNetworkAdapter(int slot, NatAdapter adapter) { + this.natNetworkAdapters.put((long) slot, adapter); + return this; + } + + public NetworkSpec build() { + return new NetworkSpec(natNetworkAdapters); + } + } + + + public Map getNatNetworkAdapters() { + return Collections.unmodifiableMap(natNetworkAdapters); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof VmSpec) { + NetworkSpec other = (NetworkSpec) o; + return Objects.equal(natNetworkAdapters, other.natNetworkAdapters); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(natNetworkAdapters); + } + + + @Override + public String toString() { + return "NetworkSpec{" + + "natNetworkAdapters=" + natNetworkAdapters + + '}'; + } +} diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java index 8f61cdc827..2b9a0c640e 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/VmSpec.java @@ -18,18 +18,13 @@ */ package org.jclouds.virtualbox.domain; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - +import com.google.common.base.Objects; import org.virtualbox_4_1.CleanupMode; -import com.google.common.base.Objects; +import java.util.*; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; /** * A description of a Virtual Machine in VirtualBox. @@ -41,16 +36,14 @@ public class VmSpec { private final String vmId; private final long memory; private final boolean forceOverwrite; - private final Map natNetworkAdapters; private final Set controllers; private final CleanupMode cleanupMode; - public VmSpec(String vmId, String vmName, String osTypeId, long memory, boolean forceOverwrite, Set controllers, Map natNetworkAdapters, CleanupMode cleanupMode) { + public VmSpec(String vmId, String vmName, String osTypeId, long memory, boolean forceOverwrite, Set controllers, CleanupMode cleanupMode) { checkNotNull(vmId, "vmId"); checkNotNull(vmName, "vmName"); checkArgument(memory > 0, "memory must be > 0"); checkNotNull(controllers, "controllers"); - checkNotNull(natNetworkAdapters, "natNetworkAdapters"); checkNotNull(cleanupMode, "cleanupMode"); this.vmId = vmId; this.vmName = vmName; @@ -58,7 +51,6 @@ public class VmSpec { this.memory = memory; this.controllers = controllers; this.forceOverwrite = forceOverwrite; - this.natNetworkAdapters = natNetworkAdapters; this.cleanupMode = cleanupMode; } @@ -74,10 +66,9 @@ public class VmSpec { private String id; private String osTypeId = ""; private boolean forceOverwrite; - private Map natNetworkAdapters = new HashMap(); private long memory; private CleanupMode cleanUpMode; - + public Builder controller(StorageController controller) { controllers.add(controller); return this; @@ -103,30 +94,24 @@ public class VmSpec { return this; } - public Builder natNetworkAdapter(int slot, NatAdapter adapter) { - this.natNetworkAdapters.put((long) slot, adapter); - return this; - } - public Builder memoryMB(int memorySize) { this.memory = (long) memorySize; return this; } - + public Builder cleanUpMode(CleanupMode cleanupMode) { this.cleanUpMode = cleanupMode; return this; - } + } public VmSpec build() { checkNotNull(name, "name"); checkNotNull(id, "id"); checkArgument(memory > 0, "Memory must be set"); - return new VmSpec(id, name, osTypeId, memory, forceOverwrite, controllers, natNetworkAdapters, cleanUpMode); + return new VmSpec(id, name, osTypeId, memory, forceOverwrite, controllers, cleanUpMode); } - - } + public String getVmId() { return vmId; } @@ -151,10 +136,6 @@ public class VmSpec { return Collections.unmodifiableSet(controllers); } - public Map getNatNetworkAdapters() { - return Collections.unmodifiableMap(natNetworkAdapters); - } - public CleanupMode getCleanupMode() { return cleanupMode; } @@ -169,7 +150,6 @@ public class VmSpec { Objects.equal(osTypeId, other.osTypeId) && Objects.equal(memory, other.memory) && Objects.equal(forceOverwrite, other.forceOverwrite) && - Objects.equal(natNetworkAdapters, other.natNetworkAdapters) && Objects.equal(controllers, other.controllers) && Objects.equal(cleanupMode, other.cleanupMode); } @@ -178,7 +158,7 @@ public class VmSpec { @Override public int hashCode() { - return Objects.hashCode(vmId, vmName, osTypeId, memory, forceOverwrite, natNetworkAdapters, controllers); + return Objects.hashCode(vmId, vmName, osTypeId, memory, forceOverwrite, controllers); } @Override @@ -189,7 +169,6 @@ public class VmSpec { ", memory='" + memory + '\'' + ", vmId='" + vmId + '\'' + ", forceOverwrite=" + forceOverwrite + - ", natNetworkAdapters=" + natNetworkAdapters + ", controllers=" + controllers + ", cleanupMode=" + cleanupMode + '}'; diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java index 9d86fd6a3a..e128bfbe44 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java @@ -18,30 +18,20 @@ */ package org.jclouds.virtualbox.functions; -import static com.google.common.base.Preconditions.checkState; -import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; -import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; -import static org.jclouds.virtualbox.util.MachineUtils.applyForMachine; -import static org.jclouds.virtualbox.util.MachineUtils.lockSessionOnMachineAndApply; -import static org.virtualbox_4_1.LockType.Shared; - -import java.net.URI; -import java.util.List; - -import javax.annotation.Resource; -import javax.inject.Named; -import javax.inject.Singleton; - +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.inject.Inject; import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.callables.RunScriptOnNode.Factory; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.logging.Logger; import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.ssh.SshClient; -import org.jclouds.virtualbox.Preconfiguration; import org.jclouds.virtualbox.domain.ExecutionType; +import org.jclouds.virtualbox.domain.IMachineSpec; +import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.settings.KeyboardScancodes; import org.virtualbox_4_1.IMachine; @@ -49,16 +39,19 @@ import org.virtualbox_4_1.IProgress; import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.VirtualBoxManager; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Splitter; -import com.google.common.base.Supplier; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.inject.Inject; +import javax.annotation.Resource; +import javax.inject.Named; +import javax.inject.Singleton; +import java.net.URI; + +import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; +import static org.jclouds.virtualbox.util.MachineUtils.applyForMachine; +import static org.jclouds.virtualbox.util.MachineUtils.lockSessionOnMachineAndApply; +import static org.virtualbox_4_1.LockType.Shared; @Singleton -public class CreateAndInstallVm implements Function { +public class CreateAndInstallVm implements Function { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) @@ -66,9 +59,7 @@ public class CreateAndInstallVm implements Function { private final Supplier manager; private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists; - private final ValueOfConfigurationKeyOrNull valueOfConfigurationKeyOrNull; - private final Supplier preconfiguration; private final Predicate sshResponds; private final ExecutionType executionType; @@ -78,66 +69,53 @@ public class CreateAndInstallVm implements Function { private final Function sshClientForIMachine; @Inject - public CreateAndInstallVm( - Supplier manager, - CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists, - ValueOfConfigurationKeyOrNull valueOfConfigurationKeyOrNull, - Predicate sshResponds, - Function sshClientForIMachine, - Supplier host, RunScriptOnNode.Factory scriptRunner, - @Preconfiguration Supplier preconfiguration, - ExecutionType executionType) { + public CreateAndInstallVm(Supplier manager, + CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists, + Predicate sshResponds, Function sshClientForIMachine, + Supplier host, RunScriptOnNode.Factory scriptRunner, ExecutionType executionType) { this.manager = manager; this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists; - this.valueOfConfigurationKeyOrNull = valueOfConfigurationKeyOrNull; this.sshResponds = sshResponds; this.sshClientForIMachine = sshClientForIMachine; this.scriptRunner = scriptRunner; this.host = host; - this.preconfiguration = preconfiguration; this.executionType = executionType; } @Override - public IMachine apply(VmSpec vmSpec) { + public IMachine apply(IMachineSpec machineSpec) { + + VmSpec vmSpec = machineSpec.getVmSpec(); + IsoSpec isoSpec = machineSpec.getIsoSpec(); + String vmName = vmSpec.getVmName(); - // note this may not be reachable, as this likely uses the 10.2.2 address - URI preconfigurationUri = preconfiguration.get(); - String keySequence = valueOfConfigurationKeyOrNull - .apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) - .replace("PRECONFIGURATION_URL", - preconfigurationUri.toASCIIString()) - .replace("HOSTNAME", vmName); - - final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists - .apply(vmSpec); + final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(machineSpec); // Launch machine and wait for it to come online ensureMachineIsLaunched(vmName); - sendKeyboardSequence(keySequence, vmName); + URI uri = isoSpec.getPreConfigurationUri().get(); + String installationKeySequence = isoSpec.getInstallationKeySequence() + .replace("PRECONFIGURATION_URL", uri.toASCIIString()); + sendKeyboardSequence(installationKeySequence, vmName); SshClient client = sshClientForIMachine.apply(vm); logger.debug(">> awaiting installation to finish node(%s)", vmName); - checkState(sshResponds.apply(client), - "timed out waiting for guest %s to be accessible via ssh", vmName); + checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", vmName); - logger.debug("<< installation of image complete. Powering down node(%s)", - vmName); - lockSessionOnMachineAndApply(manager.get(), Shared, vmName, - new Function() { + logger.debug("<< installation of image complete. Powering down node(%s)", vmName); + lockSessionOnMachineAndApply(manager.get(), Shared, vmName, new Function() { - @Override - public Void apply(ISession session) { - IProgress powerDownProgress = session.getConsole() - .powerDown(); - powerDownProgress.waitForCompletion(-1); - return null; - } + @Override + public Void apply(ISession session) { + IProgress powerDownProgress = session.getConsole().powerDown(); + powerDownProgress.waitForCompletion(-1); + return null; + } - }); + }); return vm; } diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java index 5947b6ebe1..392911c6f9 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java @@ -36,12 +36,7 @@ import javax.inject.Singleton; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import org.jclouds.virtualbox.config.VirtualBoxConstants; -import org.jclouds.virtualbox.domain.DeviceDetails; -import org.jclouds.virtualbox.domain.HardDisk; -import org.jclouds.virtualbox.domain.IsoImage; -import org.jclouds.virtualbox.domain.NatAdapter; -import org.jclouds.virtualbox.domain.StorageController; -import org.jclouds.virtualbox.domain.VmSpec; +import org.jclouds.virtualbox.domain.*; import org.virtualbox_4_1.AccessMode; import org.virtualbox_4_1.DeviceType; import org.virtualbox_4_1.IMachine; @@ -57,7 +52,7 @@ import com.google.common.base.Supplier; * @author Mattias Holmqvist */ @Singleton -public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Function { +public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Function { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) @@ -74,9 +69,9 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Functi } @Override - public IMachine apply(@Nullable VmSpec launchSpecification) { + public IMachine apply(@Nullable IMachineSpec launchSpecification) { final IVirtualBox vBox = manager.get().getVBox(); - String vmName = launchSpecification.getVmName(); + String vmName = launchSpecification.getVmSpec().getVmName(); try { vBox.findMachine(vmName); throw new IllegalStateException("Machine " + vmName + " is already registered."); @@ -92,17 +87,20 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Functi return e.getMessage().contains("VirtualBox error: Could not find a registered machine named "); } - private IMachine createMachine(IVirtualBox vBox, VmSpec vmSpec) { + private IMachine createMachine(IVirtualBox vBox, IMachineSpec machineSpec) { + VmSpec vmSpec = machineSpec.getVmSpec(); String settingsFile = vBox.composeMachineFilename(vmSpec.getVmName(), workingDir); IMachine newMachine = vBox.createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(), vmSpec.getVmId(), vmSpec.isForceOverwrite()); manager.get().getVBox().registerMachine(newMachine); - ensureConfiguration(vmSpec); + ensureConfiguration(machineSpec); return newMachine; } - private void ensureConfiguration(VmSpec vmSpec) { + private void ensureConfiguration(IMachineSpec machineSpec) { + VmSpec vmSpec = machineSpec.getVmSpec(); + NetworkSpec networkSpec = machineSpec.getNetworkSpec(); String vmName = vmSpec.getVmName(); // Change RAM @@ -118,7 +116,7 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Functi setupDvdsForController(vmSpec, vmName, controller); // NAT - Map natNetworkAdapters = vmSpec.getNatNetworkAdapters(); + Map natNetworkAdapters = networkSpec.getNatNetworkAdapters(); for (Map.Entry natAdapterAndSlot : natNetworkAdapters.entrySet()) { long slotId = natAdapterAndSlot.getKey(); NatAdapter natAdapter = natAdapterAndSlot.getValue(); diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java index 3b1596f089..8d9ec5d11c 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/domain/VmSpecTest.java @@ -70,9 +70,6 @@ public class VmSpecTest { .osTypeId("Ubuntu") .memoryMB(1024) .cleanUpMode(CleanupMode.Full) - .natNetworkAdapter( - 0, - NatAdapter.builder().tcpRedirectRule("localhost", 2222, "", 22).build()) .forceOverwrite(true) .controller( StorageController.builder().name("Controller") diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java index d4558d151c..e71553a2a8 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java @@ -22,10 +22,9 @@ package org.jclouds.virtualbox.functions; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.testng.Assert.assertEquals; +import com.google.inject.Injector; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; -import org.jclouds.virtualbox.domain.HardDisk; -import org.jclouds.virtualbox.domain.StorageController; -import org.jclouds.virtualbox.domain.VmSpec; +import org.jclouds.virtualbox.domain.*; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; @@ -45,7 +44,8 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends Ba private static final boolean IS_LINKED_CLONE = true; private VmSpec clonedVmSpec; - private VmSpec sourceVmSpec; + private IMachineSpec sourceMachineSpec; + private CleanupMode mode = CleanupMode.Full; @@ -53,22 +53,25 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends Ba @BeforeClass(groups = "live") public void setupClient() { super.setupClient(); - String sourceName = VIRTUALBOX_IMAGE_PREFIX - + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName()); - String cloneName = VIRTUALBOX_IMAGE_PREFIX - + "Clone#" + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName() - ); + String sourceName = VIRTUALBOX_IMAGE_PREFIX + + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName()); + String cloneName = VIRTUALBOX_IMAGE_PREFIX + + "Clone#" + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName() + ); StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE) - .attachISO(0, 0, operatingSystemIso).attachHardDisk( - HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).autoDelete(true).build()).attachISO(1, 1, - guestAdditionsIso).build(); + .attachISO(0, 0, operatingSystemIso).attachHardDisk( + HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).autoDelete(true).build()).attachISO(1, 1, + guestAdditionsIso).build(); - sourceVmSpec = VmSpec.builder().id(sourceName).name(sourceName).osTypeId("").memoryMB(512).cleanUpMode( - CleanupMode.Full).controller(ideController).forceOverwrite(true).build(); + VmSpec sourceVmSpec = VmSpec.builder().id(sourceName).name(sourceName).osTypeId("").memoryMB(512).cleanUpMode( + CleanupMode.Full).controller(ideController).forceOverwrite(true).build(); + IsoSpec isoSpec = IsoSpec.builder().build(); + NetworkSpec networkSpec = NetworkSpec.builder().build(); + sourceMachineSpec = IMachineSpec.builder().iso(isoSpec).vm(sourceVmSpec).network(networkSpec).build(); clonedVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(mode) - .forceOverwrite(true).build(); + .forceOverwrite(true).build(); } @Test @@ -83,10 +86,10 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends Ba } IMachine clone = new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(manager, workingDir, clonedVmSpec, - IS_LINKED_CLONE).apply(source); + IS_LINKED_CLONE).apply(source); assertEquals(clone.getName(), clonedVmSpec.getVmName()); } finally { - for (VmSpec spec : ImmutableSet.of(clonedVmSpec, sourceVmSpec)) + for (VmSpec spec : ImmutableSet.of(clonedVmSpec, sourceMachineSpec.getVmSpec())) undoVm(spec); } @@ -94,11 +97,12 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends Ba private IMachine getSourceNode() { try { - return context.utils().injector().getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply( - sourceVmSpec); + Injector injector = context.utils().injector(); + return injector.getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply( + sourceMachineSpec); } catch (IllegalStateException e) { // already created - return manager.get().getVBox().findMachine(sourceVmSpec.getVmId()); + return manager.get().getVBox().findMachine(sourceMachineSpec.getVmSpec().getVmId()); } } } \ No newline at end of file diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java index b3249d1376..911bab1f6d 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java @@ -19,28 +19,19 @@ package org.jclouds.virtualbox.functions; -import static com.google.common.base.Predicates.equalTo; -import static com.google.common.collect.Iterables.any; -import static com.google.common.collect.Iterables.transform; -import static org.testng.Assert.assertTrue; -import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; - -import java.util.Map; -import java.util.Set; - -import javax.annotation.Nullable; - +import com.google.common.base.CaseFormat; +import com.google.common.base.Function; +import com.google.inject.Guice; +import com.google.inject.Injector; import org.jclouds.compute.config.BaseComputeServiceContextModule; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.json.Json; import org.jclouds.json.config.GsonModule; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; -import org.jclouds.virtualbox.domain.HardDisk; -import org.jclouds.virtualbox.domain.NatAdapter; -import org.jclouds.virtualbox.domain.StorageController; -import org.jclouds.virtualbox.domain.VmSpec; +import org.jclouds.virtualbox.domain.*; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -48,9 +39,16 @@ import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.StorageBus; -import com.google.common.base.CaseFormat; -import com.google.common.base.Function; -import com.google.inject.Guice; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Predicates.equalTo; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.transform; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; +import static org.testng.Assert.assertTrue; /** * @author Andrea Turli, Mattias Holmqvist @@ -68,11 +66,11 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { @BeforeClass(groups = "live") public void setupClient() { super.setupClient(); - String vmName = VIRTUALBOX_IMAGE_PREFIX - + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName()); + String vmName = VIRTUALBOX_IMAGE_PREFIX + + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName()); HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true) - .controllerPort(0).deviceSlot(1).build(); + .controllerPort(0).deviceSlot(1).build(); StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE) .attachISO(0, 0, operatingSystemIso) .attachHardDisk(hardDisk) @@ -80,14 +78,26 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { vmSpecification = VmSpec.builder().id("jclouds-image-iso-1").name(vmName).memoryMB(512).osTypeId("") .controller(ideController) .forceOverwrite(true) - .cleanUpMode(CleanupMode.Full) - .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build()).build(); + .cleanUpMode(CleanupMode.Full).build(); undoVm(vmSpecification); } public void testCreateImageMachineFromIso() throws Exception { + Injector injector = context.utils().injector(); + Function configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class); - IMachine imageMachine = context.utils().injector().getInstance(CreateAndInstallVm.class).apply(vmSpecification); + IMachineSpec machineSpec = IMachineSpec.builder().vm(vmSpecification) + .iso(IsoSpec.builder() + .sourcePath(operatingSystemIso) + .installationScript(configProperties + .apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) + .replace("HOSTNAME", vmSpecification.getVmName())) + .preConfiguration(preconfigurationUri) + .build()) + .network(NetworkSpec.builder() + .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build()) + .build()).build(); + IMachine imageMachine = injector.getInstance(CreateAndInstallVm.class).apply(machineSpec); IMachineToImage iMachineToImage = new IMachineToImage(manager, map); Image newImage = iMachineToImage.apply(imageMachine); @@ -107,6 +117,7 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { } }; } + @Override @AfterClass(groups = "live") protected void tearDown() throws Exception { diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java index 9f8664d64c..36bdbe2ce0 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java @@ -21,11 +21,9 @@ package org.jclouds.virtualbox.functions; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; +import com.google.inject.Injector; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; -import org.jclouds.virtualbox.domain.ErrorCode; -import org.jclouds.virtualbox.domain.HardDisk; -import org.jclouds.virtualbox.domain.StorageController; -import org.jclouds.virtualbox.domain.VmSpec; +import org.jclouds.virtualbox.domain.*; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; @@ -47,38 +45,62 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends B super.setupClient(); ideControllerName = "IDE Controller"; mode = CleanupMode.Full; - ideController = StorageController.builder().name(ideControllerName).bus(StorageBus.IDE).attachISO(0, 0, - operatingSystemIso).attachHardDisk( - HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).build()).attachISO(1, 1, - guestAdditionsIso).build(); + ideController = StorageController.builder().name(ideControllerName).bus(StorageBus.IDE) + .attachISO(0, 0, operatingSystemIso) + .attachHardDisk(HardDisk.builder().diskpath(adminDisk).controllerPort(0).deviceSlot(1).build()).attachISO(1, 1, + guestAdditionsIso).build(); } @Test public void testCreateNewMachine() throws Exception { String vmName = "jclouds-test-create-1-node"; - VmSpec launchSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).controller(ideController) - .cleanUpMode(mode).osTypeId("Debian").forceOverwrite(true).build(); - undoVm(launchSpecification); + VmSpec vmSpec = VmSpec.builder() + .id(vmName) + .name(vmName) + .memoryMB(512) + .controller(ideController) + .cleanUpMode(mode) + .osTypeId("Debian") + .forceOverwrite(true).build(); + IMachineSpec machineSpec = IMachineSpec.builder() + .iso(IsoSpec.builder() + .sourcePath(operatingSystemIso) + .installationScript("") + .preConfiguration(preconfigurationUri) + .build()) + .vm(vmSpec) + .network(NetworkSpec.builder().build()).build(); + undoVm(vmSpec); try { IMachine debianNode = context.utils().injector().getInstance( - CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply(launchSpecification); + CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply(machineSpec); IMachine machine = manager.get().getVBox().findMachine(vmName); assertEquals(debianNode.getName(), machine.getName()); } finally { - undoVm(launchSpecification); + undoVm(vmSpec); } } @Test public void testCreateNewMachineWithBadOsType() throws Exception { String vmName = "jclouds-test-create-2-node"; - VmSpec launchSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).controller(ideController) - .cleanUpMode(mode).osTypeId("SomeWeirdUnknownOs").forceOverwrite(true).build(); - - undoVm(launchSpecification); + VmSpec vmSpec = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).controller(ideController) + .cleanUpMode(mode).osTypeId("SomeWeirdUnknownOs").forceOverwrite(true).build(); + IsoSpec isoSpec = IsoSpec.builder() + .sourcePath(operatingSystemIso) + .installationScript("") + .preConfiguration(preconfigurationUri) + .build(); + NetworkSpec networkSpec = NetworkSpec.builder().build(); + IMachineSpec machineSpec = IMachineSpec.builder() + .iso(isoSpec) + .vm(vmSpec) + .network(networkSpec).build(); + undoVm(vmSpec); try { - context.utils().injector().getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class).apply( - launchSpecification); + Injector injector = context.utils().injector(); + injector.getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class) + .apply(machineSpec); fail(); } catch (VBoxException e) { ErrorCode errorCode = ErrorCode.valueOf(e); @@ -86,7 +108,7 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends B // if osTypeId is not found. assertEquals(errorCode, ErrorCode.VBOX_E_OBJECT_NOT_FOUND); } finally { - undoVm(launchSpecification); + undoVm(vmSpec); } } diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java index d285e3fb22..a0918deddd 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest.java @@ -27,7 +27,14 @@ import static org.easymock.classextension.EasyMock.createNiceMock; import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.verify; +import com.google.common.base.Supplier; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; import org.easymock.EasyMock; +import org.jclouds.virtualbox.Preconfiguration; +import org.jclouds.virtualbox.domain.IMachineSpec; +import org.jclouds.virtualbox.domain.IsoSpec; +import org.jclouds.virtualbox.domain.NetworkSpec; import org.jclouds.virtualbox.domain.VmSpec; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; @@ -40,6 +47,8 @@ import org.virtualbox_4_1.VirtualBoxManager; import com.google.common.base.Suppliers; +import java.net.URI; + /** * @author Mattias Holmqvist */ @@ -51,11 +60,14 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest { VirtualBoxManager manager = createMock(VirtualBoxManager.class); IVirtualBox vBox = createMock(IVirtualBox.class); + Supplier preconfiguration = createNiceMock(Supplier.class); String vmName = "jclouds-image-my-ubuntu-image"; - - VmSpec launchSpecification = VmSpec.builder().id(vmName).name(vmName).osTypeId("").memoryMB(1024).cleanUpMode( - CleanupMode.Full).build(); - + VmSpec vmSpec = VmSpec.builder().id(vmName).name(vmName).osTypeId("").memoryMB(1024).cleanUpMode( + CleanupMode.Full).build(); + IMachineSpec machineSpec = IMachineSpec.builder() + .iso(IsoSpec.builder().sourcePath("some.iso").installationScript("").preConfiguration(preconfiguration).build()) + .vm(vmSpec) + .network(NetworkSpec.builder().build()).build(); IMachine createdMachine = createMock(IMachine.class); ISession session = createMock(ISession.class); @@ -71,9 +83,9 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest { expect(vBox.findMachine(vmName)).andThrow(vBoxException); expect(vBox.createMachine(anyString(), eq(vmName), anyString(), anyString(), anyBoolean())).andReturn( - createdMachine).anyTimes(); + createdMachine).anyTimes(); vBox.registerMachine(createdMachine); - + expect(vBox.findMachine(vmName)).andReturn(createdMachine).anyTimes(); expect(manager.getSessionObject()).andReturn(session); expect(session.getMachine()).andReturn(createdMachine); @@ -81,13 +93,13 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest { createdMachine.setMemorySize(1024l); createdMachine.saveSettings(); session.unlockMachine(); - - + + //TODO: this mock test is not finished. - + replay(manager, createdMachine, vBox, session); - new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(launchSpecification); + new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(machineSpec); verify(manager, createdMachine, vBox, session); } @@ -97,6 +109,7 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest { VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class); IVirtualBox vBox = createNiceMock(IVirtualBox.class); + Supplier preconfiguration = createNiceMock(Supplier.class); String vmName = "jclouds-image-my-ubuntu-image"; IMachine registeredMachine = createMock(IMachine.class); @@ -107,8 +120,16 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest { replay(manager, vBox); VmSpec launchSpecification = VmSpec.builder().id("").name(vmName).osTypeId("").memoryMB(1024).cleanUpMode( - CleanupMode.Full).build(); - new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(launchSpecification); + CleanupMode.Full).build(); + + IMachineSpec machineSpec = IMachineSpec.builder() + .iso(IsoSpec.builder() + .sourcePath("some.iso") + .installationScript("dostuff") + .preConfiguration(preconfiguration).build()) + .vm(launchSpecification) + .network(NetworkSpec.builder().build()).build(); + new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(machineSpec); } @Test(expectedExceptions = VBoxException.class) @@ -116,6 +137,7 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest { VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class); IVirtualBox vBox = createNiceMock(IVirtualBox.class); + Supplier preconfiguration = createNiceMock(Supplier.class); String vmName = "jclouds-image-my-ubuntu-image"; String errorMessage = "VirtualBox error: Soem other VBox error"; @@ -129,12 +151,20 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsTest { replay(manager, vBox); VmSpec launchSpecification = VmSpec.builder().id("").name(vmName).osTypeId("").cleanUpMode(CleanupMode.Full) - .memoryMB(1024).build(); - new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(launchSpecification); + .memoryMB(1024).build(); + IMachineSpec machineSpec = IMachineSpec.builder() + .iso(IsoSpec.builder() + .sourcePath("some.iso") + .installationScript("dostuff") + .preConfiguration(preconfiguration).build()) + .vm(launchSpecification) + .network(NetworkSpec.builder().build()).build(); + + new CreateAndRegisterMachineFromIsoIfNotAlreadyExists(Suppliers.ofInstance(manager), "/tmp/workingDir").apply(machineSpec); } private String anyString() { - return EasyMock. anyObject(); + return EasyMock.anyObject(); } } diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java index 3946717d24..b6382fd5aa 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/UnregisterMachineIfExistsAndDeleteItsMediaTest.java @@ -28,10 +28,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.jclouds.virtualbox.domain.HardDisk; -import org.jclouds.virtualbox.domain.NatAdapter; -import org.jclouds.virtualbox.domain.StorageController; -import org.jclouds.virtualbox.domain.VmSpec; +import org.jclouds.virtualbox.domain.*; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; @@ -66,8 +63,7 @@ public class UnregisterMachineIfExistsAndDeleteItsMediaTest { VmSpec vmSpecification = VmSpec.builder().id(vmId).name(vmName).memoryMB(512).osTypeId(osTypeId) .controller(ideController) .forceOverwrite(true) - .cleanUpMode(CleanupMode.Full) - .natNetworkAdapter(0, NatAdapter.builder().tcpRedirectRule("127.0.0.1", 2222, "", 22).build()).build(); + .cleanUpMode(CleanupMode.Full).build(); expect(manager.getVBox()).andReturn(vBox).anyTimes(); expect(vBox.findMachine(vmName)).andReturn(registeredMachine); diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java index b4a86d8bcf..3459020af7 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/IsLinkedClonesLiveTest.java @@ -22,10 +22,9 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; +import com.google.inject.Injector; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; -import org.jclouds.virtualbox.domain.HardDisk; -import org.jclouds.virtualbox.domain.StorageController; -import org.jclouds.virtualbox.domain.VmSpec; +import org.jclouds.virtualbox.domain.*; import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists; import org.jclouds.virtualbox.functions.CreateAndRegisterMachineFromIsoIfNotAlreadyExists; import org.testng.annotations.AfterMethod; @@ -53,7 +52,7 @@ public class IsLinkedClonesLiveTest extends BaseVirtualBoxClientLiveTest { private String cloneName; private String vmName; private StorageController masterStorageController; - private VmSpec masterSpec; + private IMachineSpec masterMachineSpec; private VmSpec cloneSpec; @Override @@ -70,8 +69,15 @@ public class IsLinkedClonesLiveTest extends BaseVirtualBoxClientLiveTest { .build(); masterStorageController = StorageController.builder().name(ideControllerName).bus(StorageBus.IDE).attachISO(0, 0, operatingSystemIso).attachHardDisk(hardDisk).attachISO(1, 1, guestAdditionsIso).build(); - masterSpec = VmSpec.builder().id(vmId).name(vmName).memoryMB(512).osTypeId(osTypeId).controller( + VmSpec masterSpec = VmSpec.builder().id(vmId).name(vmName).memoryMB(512).osTypeId(osTypeId).controller( masterStorageController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); + masterMachineSpec = IMachineSpec.builder() + .iso(IsoSpec.builder() + .sourcePath(operatingSystemIso) + .preConfiguration(preconfigurationUri) + .installationScript("").build()) + .vm(masterSpec) + .network(NetworkSpec.builder().build()).build(); cloneSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full) .forceOverwrite(true).build(); @@ -80,8 +86,9 @@ public class IsLinkedClonesLiveTest extends BaseVirtualBoxClientLiveTest { @Test public void testLinkedClone() { - IMachine master = context.utils().injector().getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class) - .apply(masterSpec); + Injector injector = context.utils().injector(); + IMachine master = injector.getInstance(CreateAndRegisterMachineFromIsoIfNotAlreadyExists.class) + .apply(masterMachineSpec); IMachine clone = new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(manager, workingDir, cloneSpec, IS_LINKED_CLONE).apply(master); @@ -102,7 +109,7 @@ public class IsLinkedClonesLiveTest extends BaseVirtualBoxClientLiveTest { @BeforeMethod @AfterMethod void cleanUpVms() { - for (VmSpec spec : ImmutableSet.of(cloneSpec, masterSpec)) + for (VmSpec spec : ImmutableSet.of(cloneSpec, masterMachineSpec.getVmSpec())) this.undoVm(spec); } } From 181f1de4fd1eda7953438a0f7b5c2a9192bb6a92 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 15:30:34 -0800 Subject: [PATCH 75/82] updated clojure option map for compute2 --- .../src/main/clojure/org/jclouds/compute2.clj | 83 +++++++++++++------ 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/compute/src/main/clojure/org/jclouds/compute2.clj b/compute/src/main/clojure/org/jclouds/compute2.clj index 09489edc65..bb02907863 100644 --- a/compute/src/main/clojure/org/jclouds/compute2.clj +++ b/compute/src/main/clojure/org/jclouds/compute2.clj @@ -325,10 +325,12 @@ Here's an example of creating and running a small linux node in the group webser kw-memfn-0arg [:smallest :fastest :biggest :any]) (make-option-map kw-memfn-1arg - [:os-family :location-id :architecture :image-id :hardware-id - :os-name-matches :os-version-matches :os-description-matches - :os-64-bit :image-version-matches :image-name-matches - :image-description-matches :min-cores :min-ram]))) + [:from-hardware :from-image :from-template + :os-family :location-id :image-id :hardware-id + :os-name-matches :os-description-matches :os-version-matches + :os-arch-matches :os-64-bit :image-name-matches + :image-version-matches :image-description-matches :image-matches + :min-cores :min-ram]))) (def ^{:doc "TemplateOptions functions" :private true} @@ -336,23 +338,56 @@ Here's an example of creating and running a small linux node in the group webser (merge (make-option-map kw-memfn-0arg - [:destroy-on-error :enable-monitoring :no-placement-group :no-key-pair - :with-details]) + [;; ec2 trmk-ecloud trmk-vcloudexpress + :no-key-pair + ;; aws-ec2 + :enable-monitoring :no-placement-group]) (make-option-map kw-memfn-1arg - [:run-script :install-private-key :authorize-public-key - :override-credentials-with :override-login-user-with - :override-login-credential-with - ;; aws ec2 options - :spot-price :spot-options :placement-group :subnet-id - :block-device-mappings :unmapDeviceNamed :security-groups - :key-pair :user-data]) - (make-option-map kw-memfn-varargs [:inbound-ports]) + [;; RunScriptOptions + ;; deprecated + :override-credentials-with + :override-login-credentials + ;; deprecated + :override-login-user-with + :override-login-user + ;; deprecated + :override-login-credential-with + :override-login-password :override-login-privateKey + :override-authenticate-sudo + + :name-task :run-as-root :wrap-in-init-script :block-on-complete + :block-on-port + ;; TemplateOptions + :run-script :install-private-key :authorize-public-key :tags + ;; cloudstack + :security-group-id :network-id :network-ids :setup-static-nat + :ip-on-default-network :ips-to-networks + ;; ec2 + :security-groups :user-data :block-device-mappings + :unmap-device-named + ;; cloudstack ec2 + :key-pair + ;; aws-ec2 + :placement-group :subnet-id :spot-price :spot-options + ;; cloudstack aws-ec2 + :security-group-ids + ;; softlayer + :domain-name + ;; trmk-ecloud trmk-vcloudexpress + :ssh-key-fingerprint + ;; vcloud + :description :customization-script :ip-address-allocation-mode]) + (make-option-map + kw-memfn-varargs + [;; from TemplateOptions + :inbound-ports]) (make-option-map kw-memfn-2arg - [:block-on-port - ;; aws ec2 options - :map-ephemeral-device-to-device-name]) + [;; from TemplateOptions + :block-on-port + ;; ec2 options + :map-ephemeral-device-to-device-name]) {:map-ebs-snapshot-to-device-name (kw-memfn-apply :map-ebs-snapshot-to-device-name device-name snapshot-id size-in-gib delete-on-termination) @@ -384,17 +419,17 @@ Here's an example of creating and running a small linux node in the group webser The :os-family key expects a keyword version of OsFamily, eg. :os-family :ubuntu. -The :smallest, :fastest, :biggest, :any, and :destroy-on-error keys expect a +The :smallest, :fastest, :biggest, and :any keys expect a boolean value. Options correspond to TemplateBuilder methods." [#^ComputeService compute - {:keys [os-family location-id architecture image-id hardware-id - os-name-matches os-version-matches os-description-matches - os-64-bit image-version-matches image-name-matches - image-description-matches min-cores min-ram - run-script install-private-key authorize-public-key - inbound-ports smallest fastest biggest any destroy-on-error] + {:keys [from-hardware from-image from-template + os-family location-id image-id hardware-id + os-name-matches os-description-matches os-version-matches + os-arch-matches os-64-bit mage-name-matches + image-version-matches image-description-matches image-matches + min-cores min-ram smallest fastest biggest any] :as options}] (let [builder (.. compute (templateBuilder))] (doseq [[option value] options] From 15af98ba02ded71ab5ebf9a0929a574193abb385 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 15:30:58 -0800 Subject: [PATCH 76/82] fixed test glitch in azureblob --- .../java/org/jclouds/azureblob/AzureBlobClientLiveTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java b/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java index 22ecdfcd66..dc84cf6044 100644 --- a/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java +++ b/providers/azureblob/src/test/java/org/jclouds/azureblob/AzureBlobClientLiveTest.java @@ -50,6 +50,7 @@ import org.jclouds.io.Payloads; import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.rest.BaseRestClientLiveTest; import org.jclouds.util.Strings2; +import org.jclouds.util.Throwables2; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; @@ -320,8 +321,9 @@ public class AzureBlobClientLiveTest extends BaseRestClientLiveTest { client.getBlob(privateContainer, object.getProperties().getName(), GetOptions.Builder .ifETagDoesntMatch(newEtag)); } catch (Exception e) { - assertEquals(e.getCause().getClass(), HttpResponseException.class); - assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 304); + HttpResponseException httpEx = Throwables2.getFirstThrowableOfType(e, HttpResponseException.class); + assert (httpEx != null) : "expected http exception, not " + e; + assertEquals(httpEx.getResponse().getStatusCode(), 304); } // Matching ETag TODO this shouldn't fail!!! From db271da687e4496c7c3d28ffcb14777db3f58ea7 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 15:31:22 -0800 Subject: [PATCH 77/82] vcloud does set hostname --- .../BluelockVCloudZone01ComputeServiceLiveTest.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java b/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java index 7ba53f8131..fbed5ff729 100644 --- a/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java +++ b/providers/bluelock-vcloud-zone01/src/test/java/org/jclouds/bluelock/vcloud/zone01/compute/BluelockVCloudZone01ComputeServiceLiveTest.java @@ -18,8 +18,6 @@ */ package org.jclouds.bluelock.vcloud.zone01.compute; -import org.jclouds.compute.domain.ExecResponse; -import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.vcloud.compute.VCloudComputeServiceLiveTest; import org.testng.annotations.Test; @@ -33,10 +31,5 @@ public class BluelockVCloudZone01ComputeServiceLiveTest extends VCloudComputeSer public BluelockVCloudZone01ComputeServiceLiveTest() { provider = "bluelock-vcloud-zone01"; } - - protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) { - // hostname is not completely predictable based on node metadata - assert execResponse.getOutput().trim().equals("Ubuntu1004") : execResponse + ": " + node1; - } } From 22fc14fc09b6feef40050ff14c7cd2f92547798a Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 15:41:17 -0800 Subject: [PATCH 78/82] Issue 145:Add custom user agent --- .../http/internal/JavaUrlHttpCommandExecutorService.java | 5 ++++- .../JavaUrlHttpCommandExecutorServiceIntegrationTest.java | 2 ++ .../main/java/org/jclouds/http/apachehc/ApacheHCUtils.java | 5 +++-- .../java/org/jclouds/gae/GaeHttpCommandExecutorService.java | 6 ++++-- .../AsyncGaeHttpCommandExecutorServiceIntegrationTest.java | 1 + 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java index 19d7361d25..50ef222bad 100644 --- a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java +++ b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java @@ -51,6 +51,7 @@ import javax.net.ssl.SSLContext; import javax.ws.rs.core.HttpHeaders; import org.jclouds.Constants; +import org.jclouds.JcloudsVersion; import org.jclouds.crypto.CryptoStreams; import org.jclouds.http.HttpCommandExecutorService; import org.jclouds.http.HttpRequest; @@ -77,7 +78,9 @@ import com.google.common.io.CountingOutputStream; @Singleton public class JavaUrlHttpCommandExecutorService extends BaseHttpCommandExecutorService { - public static final String USER_AGENT = "jclouds/1.0 java/" + System.getProperty("java.version"); + public static final String USER_AGENT = String.format("jclouds/%s java/%s", JcloudsVersion.get(), System + .getProperty("java.version")); + @Resource protected Logger logger = Logger.NULL; private final Supplier untrustedSSLContextProvider; diff --git a/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java b/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java index 4e71445a40..e64008d029 100644 --- a/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java +++ b/core/src/test/java/org/jclouds/http/JavaUrlHttpCommandExecutorServiceIntegrationTest.java @@ -27,6 +27,7 @@ import java.util.Properties; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.http.internal.JavaUrlHttpCommandExecutorService; +import org.testng.annotations.Test; import com.google.inject.Module; @@ -35,6 +36,7 @@ import com.google.inject.Module; * * @author Adrian Cole */ +@Test public class JavaUrlHttpCommandExecutorServiceIntegrationTest extends BaseHttpCommandExecutorServiceIntegrationTest { protected Module createConnectionModule() { diff --git a/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java b/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java index 15b6f4f892..25e84bdfce 100644 --- a/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java +++ b/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCUtils.java @@ -43,6 +43,7 @@ import org.apache.http.entity.FileEntity; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.params.CoreProtocolPNames; +import org.jclouds.JcloudsVersion; import org.jclouds.http.HttpRequest; import org.jclouds.io.Payload; import org.jclouds.io.payloads.BasePayload; @@ -59,8 +60,8 @@ import com.google.common.base.Throwables; */ @Singleton public class ApacheHCUtils { - - public static final String USER_AGENT = "jclouds/1.0 httpclient/4.0.1"; + //TODO: look up httpclient version + public static final String USER_AGENT = String.format("jclouds/%s httpclient/%s", JcloudsVersion.get(), "4.1.1"); public static HttpUriRequest convertToApacheRequest(HttpRequest request) { HttpUriRequest apacheRequest; diff --git a/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java b/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java index 929bafdf88..2ca19fa727 100644 --- a/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java +++ b/drivers/gae/src/main/java/org/jclouds/gae/GaeHttpCommandExecutorService.java @@ -26,6 +26,7 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.Constants; +import org.jclouds.JcloudsVersion; import org.jclouds.concurrent.SingleThreaded; import org.jclouds.http.HttpCommandExecutorService; import org.jclouds.http.HttpRequest; @@ -50,8 +51,9 @@ import com.google.common.annotations.VisibleForTesting; @SingleThreaded @Singleton public class GaeHttpCommandExecutorService extends BaseHttpCommandExecutorService { - public static final String USER_AGENT = "jclouds/1.0 urlfetch/1.3.5"; - + //TODO: look up gae version + public static final String USER_AGENT = String.format("jclouds/%s urlfetch/%s", JcloudsVersion.get(), "1.4.3"); + private final URLFetchService urlFetchService; private final ConvertToGaeRequest convertToGaeRequest; private final ConvertToJcloudsResponse convertToJcloudsResponse; diff --git a/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java b/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java index 0d1113c040..2971e88031 100644 --- a/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java +++ b/drivers/gae/src/test/java/org/jclouds/gae/AsyncGaeHttpCommandExecutorServiceIntegrationTest.java @@ -63,6 +63,7 @@ import com.google.inject.Module; * * @author Adrian Cole */ +@Test public class AsyncGaeHttpCommandExecutorServiceIntegrationTest extends BaseHttpCommandExecutorServiceIntegrationTest { Logger logger = Logger.CONSOLE; From 79e9f23b18ccd04243d19ed67bc2d836e9d8ef1c Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 17:58:54 -0800 Subject: [PATCH 79/82] removed softlayer DC --- .../softlayer/features/ProductPackageClientLiveTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java index f081155c91..ad880314ff 100644 --- a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java +++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/ProductPackageClientLiveTest.java @@ -22,7 +22,6 @@ import static org.jclouds.softlayer.predicates.ProductItemPredicates.capacity; import static org.jclouds.softlayer.predicates.ProductItemPredicates.categoryCode; import static org.jclouds.softlayer.predicates.ProductItemPredicates.units; import static org.jclouds.softlayer.predicates.ProductPackagePredicates.named; -import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -108,7 +107,6 @@ public class ProductPackageClientLiveTest extends BaseSoftLayerClientLiveTest { public void testDatacentersForCloudLayer() { ImmutableSet.Builder builder = ImmutableSet.builder(); - builder.add(Datacenter.builder().id(3).name("dal01").longName("Dallas").build()); builder.add(Datacenter.builder().id(18171).name("sea01").longName("Seattle").build()); builder.add(Datacenter.builder().id(37473).name("wdc01").longName("Washington, DC").build()); builder.add(Datacenter.builder().id(138124).name("dal05").longName("Dallas 5").build()); @@ -119,7 +117,7 @@ public class ProductPackageClientLiveTest extends BaseSoftLayerClientLiveTest { Set expected = builder.build(); Set datacenters = cloudServerProductPackage.getDatacenters(); - assertEquals(datacenters.size(), expected.size()); + assert datacenters.size() == expected.size() : datacenters; assertTrue(datacenters.containsAll(expected)); for (Datacenter dataCenter : datacenters) { From 4ce8d702ade40bfaa234fc89e694e40038d9f4c7 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 19:17:01 -0800 Subject: [PATCH 80/82] removed missing image def --- .../compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java b/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java index e2efc785e7..fc46ea9edd 100644 --- a/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java +++ b/providers/go2cloud-jhb1/src/test/java/org/jclouds/go2cloud/compute/Go2CloudJohannesburg1TemplateBuilderLiveTest.java @@ -57,7 +57,7 @@ public class Go2CloudJohannesburg1TemplateBuilderLiveTest extends BaseTemplateBu case DEBIAN: return (input.version.equals("") || input.version.equals("6.0")) && input.is64Bit; case WINDOWS: - return (input.version.equals("") || input.version.equals("2008 R2")) && input.is64Bit; + return input.version.equals("") && input.is64Bit; default: return false; } From 0d3bd741562279a32cbe87408bddb64d4ab6863d Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 19:44:22 -0800 Subject: [PATCH 81/82] increased timeout defaults on terremark --- .../trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java | 5 +++-- .../TerremarkVCloudExpressPropertiesBuilder.java | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java index 5b6e9e69e4..a3081f88fb 100644 --- a/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java +++ b/common/trmk/src/main/java/org/jclouds/trmk/vcloud_0_8/TerremarkVCloudPropertiesBuilder.java @@ -30,6 +30,7 @@ import static org.jclouds.trmk.vcloud_0_8.reference.VCloudConstants.PROPERTY_VCL import static org.jclouds.trmk.vcloud_0_8.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; import java.util.Properties; +import java.util.concurrent.TimeUnit; import org.jclouds.PropertiesBuilder; import org.jclouds.trmk.vcloud_0_8.domain.FenceMode; @@ -49,8 +50,8 @@ public class TerremarkVCloudPropertiesBuilder extends PropertiesBuilder { properties.setProperty(PROPERTY_VCLOUD_XML_SCHEMA, "http://vcloud.safesecureweb.com/ns/vcloud.xsd"); properties.setProperty("jclouds.dns_name_length_min", "1"); properties.setProperty("jclouds.dns_name_length_max", "15"); - // with ssh key injection comes another reboot. allowing more time - properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 420l * 1000l + ""); + // terremark can sometimes block extremely long times + properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, TimeUnit.MINUTES.toMillis(20) + ""); return properties; } diff --git a/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java b/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java index cb2b077d50..5c798c9b8b 100644 --- a/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java +++ b/providers/trmk-vcloudexpress/src/main/java/org/jclouds/trmk/vcloudexpress/TerremarkVCloudExpressPropertiesBuilder.java @@ -23,7 +23,6 @@ import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NAME; import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_VERSION; -import static org.jclouds.trmk.vcloud_0_8.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED; import java.util.Properties; @@ -43,7 +42,6 @@ public class TerremarkVCloudExpressPropertiesBuilder extends TerremarkVCloudProp properties.setProperty(PROPERTY_TERREMARK_EXTENSION_NAME, "vCloudExpressExtensions"); properties.setProperty(PROPERTY_TERREMARK_EXTENSION_VERSION, "1.6"); properties.setProperty(PROPERTY_ENDPOINT, "https://services.vcloudexpress.terremark.com/api"); - properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 600l * 1000l + ""); return properties; } From 69c9fd6905f838382876d41363687f254424f07f Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 15 Jan 2012 19:45:55 -0800 Subject: [PATCH 82/82] fixed null pointers --- .../compute/domain/internal/TemplateBuilderImpl.java | 3 ++- .../jclouds/compute/BaseTemplateBuilderLiveTest.java | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java index fe013d604f..6c3e0f3c3a 100644 --- a/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java +++ b/compute/src/main/java/org/jclouds/compute/domain/internal/TemplateBuilderImpl.java @@ -440,7 +440,8 @@ public class TemplateBuilderImpl implements TemplateBuilder { Ordering. natural().nullsLast()) .compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(),// Ordering. natural().nullsLast()) - .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch()).result(); + .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch(),// + Ordering. natural().nullsLast()).result(); } }; diff --git a/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java index 160c6b4229..cfd5d3f852 100644 --- a/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/BaseTemplateBuilderLiveTest.java @@ -281,12 +281,12 @@ public abstract class BaseTemplateBuilderLiveTest extends BaseVersionedServiceLi assertEquals(context.getComputeService().templateBuilder().build().getImage().getDefaultCredentials(), LoginCredentials.builder().user(user).password(pass).authenticateSudo(auth).build()); } finally { - if (context != null) + if (context != null){ + // Need to clear persisted credentials; otherwise next time a ComputeServiceContext is created + // then it will have these "foo" credentials! + context.credentialStore().clear(); context.close(); - - // Need to clear persisted credentials; otherwise next time a ComputeServiceContext is created - // then it will have these "foo" credentials! - context.credentialStore().clear(); + } } }