diff --git a/sandbox-providers/softlayer/pom.xml b/sandbox-providers/softlayer/pom.xml new file mode 100644 index 0000000000..52c3a524e5 --- /dev/null +++ b/sandbox-providers/softlayer/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.provider + softlayer + jclouds SoftLayer core + jclouds components to access SoftLayer + + + + jclouds-sona-snapshots-nexus + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + https://api.softlayer.com/rest + 3 + FIXME + FIXME + + + + org.jclouds + jclouds-core + ${project.version} + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + log4j + log4j + 1.2.16 + test + + + org.jclouds.driver + jclouds-log4j + ${project.version} + test + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + + test.softlayer.endpoint + ${test.softlayer.endpoint} + + + test.softlayer.apiversion + ${test.softlayer.apiversion} + + + test.softlayer.identity + ${test.softlayer.identity} + + + test.softlayer.credential + ${test.softlayer.credential} + + + + + + + + + + + + diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerAsyncClient.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerAsyncClient.java new file mode 100644 index 0000000000..0205a16710 --- /dev/null +++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerAsyncClient.java @@ -0,0 +1,68 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer; + +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.filters.BasicAuthentication; +import org.jclouds.rest.annotations.ExceptionParser; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.softlayer.domain.VirtualGuest; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Provides asynchronous access to SoftLayer via their REST API. + *

+ * + * @see SoftLayerClient + * @see + * @author Adrian Cole + */ +@RequestFilters(BasicAuthentication.class) +@Path("/v{jclouds.api-version}") +public interface SoftLayerAsyncClient { + + /** + * @see SoftLayerClient#listVirtualGuests + */ + @GET + @Path("/SoftLayer_Account/VirtualGuests.json") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listVirtualGuests(); + + /** + * @see SoftLayerClient#getVirtualGuest + */ + @GET + @Path("/SoftLayer_Virtual_Guest/{id}.json") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getVirtualGuest(@PathParam("id") long id); +} diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerClient.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerClient.java new file mode 100644 index 0000000000..46f5fafa02 --- /dev/null +++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerClient.java @@ -0,0 +1,53 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.softlayer.domain.VirtualGuest; + +/** + * Provides synchronous access to SoftLayer. + *

+ * + * @see SoftLayerAsyncClient + * @see + * @author Adrian Cole + */ +@Timeout(duration = 4, timeUnit = TimeUnit.SECONDS) +public interface SoftLayerClient { + + /** + * + * @return an account's associated virtual guest objects. + */ + Set listVirtualGuests(); + + /** + * + * @param id + * id of the virtual guest + * @return virtual guest or null if not found + */ + VirtualGuest getVirtualGuest(long id); + +} diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerContextBuilder.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerContextBuilder.java new file mode 100644 index 0000000000..e97f4914ba --- /dev/null +++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerContextBuilder.java @@ -0,0 +1,45 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer; + +import java.util.List; +import java.util.Properties; + +import org.jclouds.softlayer.config.SoftLayerRestClientModule; +import org.jclouds.rest.RestContextBuilder; + +import com.google.inject.Module; + +/** + * + * @author Adrian Cole + */ +public class SoftLayerContextBuilder extends + RestContextBuilder { + + public SoftLayerContextBuilder(Properties props) { + super(SoftLayerClient.class, SoftLayerAsyncClient.class, props); + } + + protected void addClientModule(List modules) { + modules.add(new SoftLayerRestClientModule()); + } + +} diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerPropertiesBuilder.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerPropertiesBuilder.java new file mode 100644 index 0000000000..dd2451c2df --- /dev/null +++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerPropertiesBuilder.java @@ -0,0 +1,47 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer; + +import static org.jclouds.Constants.PROPERTY_API_VERSION; +import static org.jclouds.Constants.PROPERTY_ENDPOINT; + +import java.util.Properties; + +import org.jclouds.PropertiesBuilder; + +/** + * Builds properties used in SoftLayer Clients + * + * @author Adrian Cole + */ +public class SoftLayerPropertiesBuilder extends PropertiesBuilder { + @Override + protected Properties defaultProperties() { + Properties properties = super.defaultProperties(); + properties.setProperty(PROPERTY_ENDPOINT, "https://api.softlayer.com/rest"); + properties.setProperty(PROPERTY_API_VERSION, "3"); + return properties; + } + + public SoftLayerPropertiesBuilder(Properties properties) { + super(properties); + } + +} diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/config/SoftLayerRestClientModule.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/config/SoftLayerRestClientModule.java new file mode 100644 index 0000000000..0de8505212 --- /dev/null +++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/config/SoftLayerRestClientModule.java @@ -0,0 +1,68 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer.config; + +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpRetryHandler; +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.http.handlers.BackoffLimitedRetryHandler; +import org.jclouds.json.config.GsonModule.DateAdapter; +import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; +import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.config.RestClientModule; +import org.jclouds.softlayer.SoftLayerAsyncClient; +import org.jclouds.softlayer.SoftLayerClient; +import org.jclouds.softlayer.handlers.SoftLayerErrorHandler; + +/** + * Configures the SoftLayer connection. + * + * @author Adrian Cole + */ +@RequiresHttp +@ConfiguresRestClient +public class SoftLayerRestClientModule extends RestClientModule { + + public SoftLayerRestClientModule() { + super(SoftLayerClient.class, SoftLayerAsyncClient.class); + } + + @Override + protected void configure() { + bind(DateAdapter.class).to(Iso8601DateAdapter.class); + super.configure(); + } + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(SoftLayerErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(SoftLayerErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(SoftLayerErrorHandler.class); + } + + @Override + protected void bindRetryHandlers() { + bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class); + } + +} diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/domain/VirtualGuest.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/domain/VirtualGuest.java new file mode 100644 index 0000000000..031c034c61 --- /dev/null +++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/domain/VirtualGuest.java @@ -0,0 +1,397 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Date; + +import com.google.common.base.CaseFormat; +import com.google.gson.annotations.SerializedName; + +/** + * The virtual guest data type presents the structure in which all virtual guests will be presented. + * Internally, the structure supports various virtualization platforms with no change to external + * interaction.
+ * A guest, also known as a virtual server or CloudLayer Computing Instance, represents an + * allocation of resources on a virtual host. + * + * @author Adrian Cole + * @see
+ */ +public class VirtualGuest implements Comparable { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + } + + public static enum State { + STARTING, RUNNING, STOPPING, STOPPED, DESTROYED, EXPUNGING, MIGRATING, ERROR, UNKNOWN, SHUTDOWNED, UNRECOGNIZED; + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + + public static State fromValue(String state) { + try { + return valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(state, "state"))); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + + } + + private long accountId = -1; + private Date createDate; + @SerializedName("dedicatedAccountHostOnlyFlag") + private boolean dedicatedAccountHostOnly; + private String domain; + private String fullyQualifiedDomainName; + private String hostname; + private long id = -1; + private Date lastVerifiedDate; + private int maxCpu = -1; + private String maxCpuUnits; + private int maxMemory = -1; + private Date metricPollDate; + private Date modifyDate; + private String notes; + @SerializedName("privateNetworkOnlyFlag") + private boolean privateNetworkOnly; + private int startCpus = -1; + private int statusId = -1; + private String uuid; + private String primaryBackendIpAddress; + private String primaryIpAddress; + + // for deserializer + VirtualGuest() { + + } + + public VirtualGuest(long accountId, Date createDate, boolean dedicatedAccountHostOnly, String domain, + String fullyQualifiedDomainName, String hostname, long id, Date lastVerifiedDate, int maxCpu, + String maxCpuUnits, int maxMemory, Date metricPollDate, Date modifyDate, String notes, + boolean privateNetworkOnly, int startCpus, int statusId, String uuid, String primaryBackendIpAddress, + String primaryIpAddress) { + this.accountId = accountId; + this.createDate = createDate; + this.dedicatedAccountHostOnly = dedicatedAccountHostOnly; + this.domain = domain; + this.fullyQualifiedDomainName = fullyQualifiedDomainName; + this.hostname = hostname; + this.id = id; + this.lastVerifiedDate = lastVerifiedDate; + this.maxCpu = maxCpu; + this.maxCpuUnits = maxCpuUnits; + this.maxMemory = maxMemory; + this.metricPollDate = metricPollDate; + this.modifyDate = modifyDate; + this.notes = notes; + this.privateNetworkOnly = privateNetworkOnly; + this.startCpus = startCpus; + this.statusId = statusId; + this.uuid = uuid; + this.primaryBackendIpAddress = primaryBackendIpAddress; + this.primaryIpAddress = primaryIpAddress; + } + + @Override + public int compareTo(VirtualGuest arg0) { + return new Long(id).compareTo(arg0.getId()); + } + + /** + * @return A computing instance's associated account id + */ + public long getAccountId() { + return accountId; + } + + /** + * @return The date a virtual computing instance was created. + */ + public Date getCreateDate() { + return createDate; + } + + /** + * @return When true this flag specifies that a compute instance is to run on hosts that only + * have guests from the same account. + */ + public boolean isDedicatedAccountHostOnly() { + return dedicatedAccountHostOnly; + } + + /** + * @return A computing instance's domain name + */ + public String getDomain() { + return domain; + } + + /** + * @return A name reflecting the hostname and domain of the computing instance. + */ + public String getFullyQualifiedDomainName() { + return fullyQualifiedDomainName; + } + + /** + * @return A virtual computing instance's hostname + */ + public String getHostname() { + return hostname; + } + + /** + * @return Unique ID for a computing instance. + */ + public long getId() { + return id; + } + + /** + * @return The last timestamp of when the guest was verified as a resident virtual machine on the + * host's hypervisor platform. + */ + + public Date getLastVerifiedDate() { + return lastVerifiedDate; + } + + /** + * @return The maximum amount of CPU resources a computing instance may utilize. + */ + public int getMaxCpu() { + return maxCpu; + } + + /** + * @return The unit of the maximum amount of CPU resources a computing instance may utilize. + */ + public String getMaxCpuUnits() { + return maxCpuUnits; + } + + /** + * @return The maximum amount of memory a computing instance may utilize. + */ + public int getMaxMemory() { + return maxMemory; + } + + /** + * @return The date of the most recent metric tracking poll performed. + */ + public Date getMetricPollDate() { + return metricPollDate; + } + + /** + * @return The date a virtual computing instance was last modified. + */ + public Date getModifyDate() { + return modifyDate; + } + + /** + * @return A small note about a cloud instance to use at your discretion. + */ + public String getNotes() { + return notes; + } + + /** + * @return Whether the computing instance only has access to the private network. + */ + public boolean isPrivateNetworkOnly() { + return privateNetworkOnly; + } + + /** + * @return The number of CPUs available to a computing instance upon startup. + */ + public int getStartCpus() { + return startCpus; + } + + /** + * @return A computing instances status ID + */ + public int getStatusId() { + return statusId; + } + + /** + * @return Unique ID for a computing instance's record on a virtualization platform. + */ + public String getUuid() { + return uuid; + } + + /** + * @return private ip address + */ + public String getPrimaryBackendIpAddress() { + return primaryBackendIpAddress; + } + + /** + * @return public ip address + */ + public String getPrimaryIpAddress() { + return primaryIpAddress; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (accountId ^ (accountId >>> 32)); + result = prime * result + ((createDate == null) ? 0 : createDate.hashCode()); + result = prime * result + (dedicatedAccountHostOnly ? 1231 : 1237); + result = prime * result + ((domain == null) ? 0 : domain.hashCode()); + result = prime * result + ((fullyQualifiedDomainName == null) ? 0 : fullyQualifiedDomainName.hashCode()); + result = prime * result + ((hostname == null) ? 0 : hostname.hashCode()); + result = prime * result + (int) (id ^ (id >>> 32)); + result = prime * result + ((lastVerifiedDate == null) ? 0 : lastVerifiedDate.hashCode()); + result = prime * result + maxCpu; + result = prime * result + ((maxCpuUnits == null) ? 0 : maxCpuUnits.hashCode()); + result = prime * result + maxMemory; + result = prime * result + ((metricPollDate == null) ? 0 : metricPollDate.hashCode()); + result = prime * result + ((modifyDate == null) ? 0 : modifyDate.hashCode()); + result = prime * result + ((notes == null) ? 0 : notes.hashCode()); + result = prime * result + ((primaryBackendIpAddress == null) ? 0 : primaryBackendIpAddress.hashCode()); + result = prime * result + ((primaryIpAddress == null) ? 0 : primaryIpAddress.hashCode()); + result = prime * result + (privateNetworkOnly ? 1231 : 1237); + result = prime * result + startCpus; + result = prime * result + statusId; + result = prime * result + ((uuid == null) ? 0 : uuid.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + VirtualGuest other = (VirtualGuest) obj; + if (accountId != other.accountId) + return false; + if (createDate == null) { + if (other.createDate != null) + return false; + } else if (!createDate.equals(other.createDate)) + return false; + if (dedicatedAccountHostOnly != other.dedicatedAccountHostOnly) + return false; + if (domain == null) { + if (other.domain != null) + return false; + } else if (!domain.equals(other.domain)) + return false; + if (fullyQualifiedDomainName == null) { + if (other.fullyQualifiedDomainName != null) + return false; + } else if (!fullyQualifiedDomainName.equals(other.fullyQualifiedDomainName)) + return false; + if (hostname == null) { + if (other.hostname != null) + return false; + } else if (!hostname.equals(other.hostname)) + return false; + if (id != other.id) + return false; + if (lastVerifiedDate == null) { + if (other.lastVerifiedDate != null) + return false; + } else if (!lastVerifiedDate.equals(other.lastVerifiedDate)) + return false; + if (maxCpu != other.maxCpu) + return false; + if (maxCpuUnits == null) { + if (other.maxCpuUnits != null) + return false; + } else if (!maxCpuUnits.equals(other.maxCpuUnits)) + return false; + if (maxMemory != other.maxMemory) + return false; + if (metricPollDate == null) { + if (other.metricPollDate != null) + return false; + } else if (!metricPollDate.equals(other.metricPollDate)) + return false; + if (modifyDate == null) { + if (other.modifyDate != null) + return false; + } else if (!modifyDate.equals(other.modifyDate)) + return false; + if (notes == null) { + if (other.notes != null) + return false; + } else if (!notes.equals(other.notes)) + return false; + if (primaryBackendIpAddress == null) { + if (other.primaryBackendIpAddress != null) + return false; + } else if (!primaryBackendIpAddress.equals(other.primaryBackendIpAddress)) + return false; + if (primaryIpAddress == null) { + if (other.primaryIpAddress != null) + return false; + } else if (!primaryIpAddress.equals(other.primaryIpAddress)) + return false; + if (privateNetworkOnly != other.privateNetworkOnly) + return false; + if (startCpus != other.startCpus) + return false; + if (statusId != other.statusId) + return false; + if (uuid == null) { + if (other.uuid != null) + return false; + } else if (!uuid.equals(other.uuid)) + return false; + return true; + } + + @Override + public String toString() { + return "[accountId=" + accountId + ", createDate=" + createDate + ", dedicatedAccountHostOnly=" + + dedicatedAccountHostOnly + ", domain=" + domain + ", fullyQualifiedDomainName=" + + fullyQualifiedDomainName + ", hostname=" + hostname + ", id=" + id + ", lastVerifiedDate=" + + lastVerifiedDate + ", maxCpu=" + maxCpu + ", maxCpuUnits=" + maxCpuUnits + ", maxMemory=" + maxMemory + + ", metricPollDate=" + metricPollDate + ", modifyDate=" + modifyDate + ", notes=" + notes + + ", primaryBackendIpAddress=" + primaryBackendIpAddress + ", primaryIpAddress=" + primaryIpAddress + + ", privateNetworkOnly=" + privateNetworkOnly + ", startCpus=" + startCpus + ", statusId=" + statusId + + ", uuid=" + uuid + "]"; + } + +} diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/handlers/SoftLayerErrorHandler.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/handlers/SoftLayerErrorHandler.java new file mode 100644 index 0000000000..72bb689893 --- /dev/null +++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/handlers/SoftLayerErrorHandler.java @@ -0,0 +1,91 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer.handlers; + +import java.io.IOException; + +import javax.annotation.Resource; +import javax.inject.Singleton; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.logging.Logger; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceNotFoundException; +import org.jclouds.util.Strings2; + +import com.google.common.base.Throwables; +import com.google.common.io.Closeables; + +/** + * This will parse and set an appropriate exception on the command object. + * + * @author Adrian Cole + * + */ +@Singleton +public class SoftLayerErrorHandler implements HttpErrorHandler { + @Resource + protected Logger logger = Logger.NULL; + + public void handleError(HttpCommand command, HttpResponse response) { + // it is important to always read fully and close streams + String message = parseMessage(response); + Exception exception = message != null ? new HttpResponseException(command, response, message) + : new HttpResponseException(command, response); + try { + message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(), + response.getStatusLine()); + switch (response.getStatusCode()) { + case 401: + case 403: + exception = new AuthorizationException(message, exception); + break; + case 404: + if (!command.getCurrentRequest().getMethod().equals("DELETE")) { + exception = new ResourceNotFoundException(message, exception); + } + break; + } + } finally { + if (response.getPayload() != null) + Closeables.closeQuietly(response.getPayload().getInput()); + command.setException(exception); + } + } + + public String parseMessage(HttpResponse response) { + if (response.getPayload() == null) + return null; + try { + return Strings2.toStringAndClose(response.getPayload().getInput()); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + try { + response.getPayload().getInput().close(); + } catch (IOException e) { + Throwables.propagate(e); + } + } + } +} diff --git a/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerAsyncClientTest.java b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerAsyncClientTest.java new file mode 100644 index 0000000000..1146d84b02 --- /dev/null +++ b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerAsyncClientTest.java @@ -0,0 +1,112 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer; + +import static org.jclouds.rest.RestContextFactory.contextSpec; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.lang.reflect.Method; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.filters.BasicAuthentication; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.rest.RestClientTest; +import org.jclouds.rest.RestContextSpec; +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.common.collect.Iterables; +import com.google.inject.TypeLiteral; + +/** + * Tests annotation parsing of {@code SoftLayerAsyncClient} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class SoftLayerAsyncClientTest extends RestClientTest { + + public void testListVirtualGuests() throws SecurityException, NoSuchMethodException, IOException { + Method method = SoftLayerAsyncClient.class.getMethod("listVirtualGuests"); + HttpRequest httpRequest = processor.createRequest(method); + + assertRequestLineEquals(httpRequest, + "GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null, null, false); + + // now make sure request filters apply by replaying + httpRequest = Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); + httpRequest = Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); + + assertRequestLineEquals(httpRequest, + "GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json HTTP/1.1"); + // for example, using basic authentication, we should get "only one" + // header + assertNonPayloadHeadersEqual(httpRequest, + "Accept: application/json\nAuthorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testGetVirtualGuest() throws SecurityException, NoSuchMethodException, IOException { + Method method = SoftLayerAsyncClient.class.getMethod("getVirtualGuest", long.class); + HttpRequest httpRequest = processor.createRequest(method, 1234); + + assertRequestLineEquals(httpRequest, + "GET https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest/1234.json HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseJson.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + @Override + protected void checkFilters(HttpRequest request) { + assertEquals(request.getFilters().size(), 1); + assertEquals(request.getFilters().get(0).getClass(), BasicAuthentication.class); + } + + @Override + protected TypeLiteral> createTypeLiteral() { + return new TypeLiteral>() { + }; + } + + @Override + public RestContextSpec createContextSpec() { + return contextSpec("softlayer", "https://api.softlayer.com/rest", "3", "", "identity", "credential", + SoftLayerClient.class, SoftLayerAsyncClient.class); + } +} diff --git a/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerClientLiveTest.java b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerClientLiveTest.java new file mode 100644 index 0000000000..93a09e5b02 --- /dev/null +++ b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerClientLiveTest.java @@ -0,0 +1,103 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.softlayer; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Properties; +import java.util.Set; + +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.rest.RestContext; +import org.jclouds.rest.RestContextFactory; +import org.jclouds.softlayer.domain.VirtualGuest; +import org.testng.annotations.AfterGroups; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; + +/** + * Tests behavior of {@code SoftLayerClient} + * + * @author Adrian Cole + */ +@Test(groups = "live") +public class SoftLayerClientLiveTest { + + private SoftLayerClient client; + private RestContext context; + + @BeforeGroups(groups = { "live" }) + public void setupClient() { + String identity = checkNotNull(System.getProperty("test.softlayer.identity"), "test.softlayer.identity"); + String credential = checkNotNull(System.getProperty("test.softlayer.credential"), "test.softlayer.credential"); + + Properties restProperties = new Properties(); + restProperties.setProperty("softlayer.contextbuilder", SoftLayerContextBuilder.class.getName()); + restProperties.setProperty("softlayer.propertiesbuilder", SoftLayerPropertiesBuilder.class.getName()); + + context = new RestContextFactory(restProperties).createContext("softlayer", identity, credential, ImmutableSet + . of(new Log4JLoggingModule())); + + client = context.getApi(); + } + + @AfterGroups(groups = "live") + void tearDown() { + if (context != null) + context.close(); + } + + @Test + public void testListVirtualGuests() throws Exception { + Set response = client.listVirtualGuests(); + assert null != response; + assertTrue(response.size() >= 0); + for (VirtualGuest vg : response) { + VirtualGuest newDetails = client.getVirtualGuest(vg.getId()); + assertEquals(vg.getId(), newDetails.getId()); + checkVirtualGuest(vg); + } + } + + private void checkVirtualGuest(VirtualGuest vg) { + assert vg.getAccountId() > 0 : vg; + assert vg.getCreateDate() != null : vg; + assert vg.getDomain() != null : vg; + assert vg.getFullyQualifiedDomainName() != null : vg; + assert vg.getHostname() != null : vg; + assert vg.getId() > 0 : vg; + assert vg.getMaxCpu() > 0 : vg; + assert vg.getMaxCpuUnits() != null : vg; + assert vg.getMaxMemory() > 0 : vg; + assert vg.getMetricPollDate() != null : vg; + assert vg.getModifyDate() != null : vg; + assert vg.getStartCpus() > 0 : vg; + assert vg.getStatusId() >= 0 : vg; + assert vg.getUuid() != null : vg; + assert vg.getPrimaryBackendIpAddress() != null : vg; + assert vg.getPrimaryIpAddress() != null : vg; + } + +} diff --git a/sandbox-providers/softlayer/src/test/resources/log4j.xml b/sandbox-providers/softlayer/src/test/resources/log4j.xml new file mode 100644 index 0000000000..c75f2a3cdf --- /dev/null +++ b/sandbox-providers/softlayer/src/test/resources/log4j.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file