diff --git a/core/src/main/resources/rest.properties b/core/src/main/resources/rest.properties index bd30efe6a3..6df8b026b5 100644 --- a/core/src/main/resources/rest.properties +++ b/core/src/main/resources/rest.properties @@ -74,6 +74,9 @@ eucalyptus-partnercloud-ec2.propertiesbuilder=org.jclouds.epc.EucalyptusPartnerC nova.contextbuilder=org.jclouds.openstack.nova.NovaContextBuilder nova.propertiesbuilder=org.jclouds.openstack.nova.NovaPropertiesBuilder +openstack-nova.contextbuilder=org.jclouds.openstack.nova.v1_1.NovaContextBuilder +openstack-nova.propertiesbuilder=org.jclouds.openstack.nova.v1_1.NovaPropertiesBuilder + cloudservers.contextbuilder=org.jclouds.cloudservers.CloudServersContextBuilder cloudservers.propertiesbuilder=org.jclouds.cloudservers.CloudServersPropertiesBuilder diff --git a/sandbox-apis/openstack-nova/pom.xml b/sandbox-apis/openstack-nova/pom.xml new file mode 100644 index 0000000000..7c912a10fd --- /dev/null +++ b/sandbox-apis/openstack-nova/pom.xml @@ -0,0 +1,152 @@ + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.3.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.api + openstack-nova + jcloud openstack-nova api + jclouds components to access an implementation of OpenStack Nova + bundle + + + http://localhost:8774/v1.1/ + v1.1 + FIXME_IDENTITY + FIXME_CREDENTIALS + + + + + + + + + + org.jclouds.common + openstack-common + ${project.version} + + + org.jclouds + jclouds-compute + ${project.version} + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.jclouds.common + openstack-common + ${project.version} + test-jar + test + + + org.jclouds + jclouds-compute + ${project.version} + test-jar + test + + + org.jclouds.driver + jclouds-sshj + ${project.version} + test + + + org.jclouds.driver + jclouds-log4j + ${project.version} + test + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.maven.surefire + surefire-testng + + + + + integration + integration-test + + test + + + + ${test.openstack-nova.endpoint} + ${test.openstack-nova.apiversion} + ${test.openstack-nova.identity} + ${test.openstack-nova.credential} + ${test.openstack-nova.image-id} + ${test.openstack-nova.image.login-user} + ${test.openstack-nova.image.authenticate-sudo} + ${test.ssh.keyfile.public} + ${test.ssh.keyfile.private} + + + + + + + + + + + + + + org.apache.felix + maven-bundle-plugin + + + ${project.artifactId} + org.jclouds.openstack.nova.v1_1.*;version="${project.version}" + org.jclouds.*;version="${project.version}",* + + + + + + + diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java new file mode 100644 index 0000000000..41e8769d4d --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java @@ -0,0 +1,40 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1; + +import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient; +import org.jclouds.rest.annotations.Delegate; + +/** + * Provides asynchronous access to Nova via their REST API. + *

+ * + * @see NovaClient + * @see + * @author Adrian Cole + */ +public interface NovaAsyncClient { + + /** + * Provides asynchronous access to Server features. + */ + @Delegate + ServerAsyncClient getServerClient(); + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaClient.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaClient.java new file mode 100644 index 0000000000..e67b9de840 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaClient.java @@ -0,0 +1,44 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1; + +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.openstack.nova.v1_1.features.ServerClient; +import org.jclouds.rest.annotations.Delegate; + +/** + * Provides synchronous access to Nova. + *

+ * + * @see NovaAsyncClient + * @see + * @author Adrian Cole + */ +@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) +public interface NovaClient { + + /** + * Provides synchronous access to Server features. + */ + @Delegate + ServerClient getServerClient(); + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaContextBuilder.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaContextBuilder.java new file mode 100644 index 0000000000..867d84fef9 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaContextBuilder.java @@ -0,0 +1,44 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1; + +import java.util.List; +import java.util.Properties; + +import org.jclouds.openstack.nova.v1_1.config.NovaRestClientModule; +import org.jclouds.rest.RestContextBuilder; + +import com.google.inject.Module; + +/** + * + * @author Adrian Cole + */ +public class NovaContextBuilder extends RestContextBuilder { + + public NovaContextBuilder(Properties props) { + super(NovaClient.class, NovaAsyncClient.class, props); + } + + @Override + protected void addClientModule(List modules) { + modules.add(new NovaRestClientModule()); + } + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaPropertiesBuilder.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaPropertiesBuilder.java new file mode 100644 index 0000000000..6c744a9654 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaPropertiesBuilder.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.openstack.nova.v1_1; + +import static org.jclouds.Constants.PROPERTY_API_VERSION; +import static org.jclouds.Constants.PROPERTY_ENDPOINT; +import static org.jclouds.Constants.PROPERTY_IDENTITY; + +import java.util.Properties; +import java.util.regex.Pattern; + +import org.jclouds.PropertiesBuilder; +import org.jclouds.util.Strings2; + +/** + * Builds properties used in Nova Clients + * + * @author Adrian Cole + */ +public class NovaPropertiesBuilder extends PropertiesBuilder { + @Override + protected Properties defaultProperties() { + Properties properties = super.defaultProperties(); + properties.setProperty(PROPERTY_ENDPOINT, "http://localhost:8774/{apiversion}/{identity}"); + properties.setProperty(PROPERTY_API_VERSION, "v1.1"); + return properties; + } + + public NovaPropertiesBuilder(Properties properties) { + super(properties); + } + + public static final Pattern IDENTITY_PATTERN = Pattern.compile("\\{identity\\}"); + public static final Pattern API_VERSION_PATTERN = Pattern.compile("\\{apiversion\\}"); + + @Override + public Properties build() { + // TODO determine if we can more elegantly do this. right now we have to + // because URI.create() doesn't allow us to build a URi with an illegal + // character '{' + String endpoint = properties.getProperty(PROPERTY_ENDPOINT); + String identity = properties.getProperty(PROPERTY_IDENTITY); + String apiVersion = properties.getProperty(PROPERTY_API_VERSION); + String withIdentity = Strings2.replaceAll(endpoint, IDENTITY_PATTERN, identity); + String withVersion = Strings2.replaceAll(withIdentity, API_VERSION_PATTERN, apiVersion); + properties.setProperty(PROPERTY_ENDPOINT, withVersion); + return super.build(); + } +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaParserModule.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaParserModule.java new file mode 100644 index 0000000000..3978500918 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaParserModule.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.openstack.nova.v1_1.config; + +import java.lang.reflect.Type; +import java.util.Map; + +import javax.inject.Singleton; + +import org.jclouds.json.config.GsonModule; +import org.jclouds.json.config.GsonModule.DateAdapter; + +import com.google.common.collect.ImmutableMap; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; + +/** + * @author Adrian Cole + */ +public class NovaParserModule extends AbstractModule { + + @Provides + @Singleton + public Map provideCustomAdapterBindings() { + return ImmutableMap.of( + ); + } + + @Override + protected void configure() { + bind(DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class); + } + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaRestClientModule.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaRestClientModule.java new file mode 100644 index 0000000000..4ec78a195c --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/config/NovaRestClientModule.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.openstack.nova.v1_1.config; + +import java.util.Map; + +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.openstack.config.OpenStackAuthenticationModule; +import org.jclouds.openstack.nova.v1_1.NovaAsyncClient; +import org.jclouds.openstack.nova.v1_1.NovaClient; +import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient; +import org.jclouds.openstack.nova.v1_1.features.ServerClient; +import org.jclouds.openstack.nova.v1_1.handlers.NovaErrorHandler; +import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.config.RestClientModule; + +import com.google.common.collect.ImmutableMap; + +/** + * Configures the Nova connection. + * + * @author Adrian Cole + */ +@RequiresHttp +@ConfiguresRestClient +public class NovaRestClientModule extends RestClientModule { + + public static final Map, Class> DELEGATE_MAP = ImmutableMap., Class> builder()// + .put(ServerClient.class, ServerAsyncClient.class)// + .build(); + + public NovaRestClientModule() { + super(NovaClient.class, NovaAsyncClient.class, DELEGATE_MAP); + } + + @Override + protected void configure() { + install(new OpenStackAuthenticationModule()); + install(new NovaParserModule()); + super.configure(); + } + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(NovaErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(NovaErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(NovaErrorHandler.class); + } + + @Override + protected void bindRetryHandlers() { + bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class); + } + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java new file mode 100644 index 0000000000..191a0aad17 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java @@ -0,0 +1,160 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.gson.annotations.SerializedName; + +/** + * Listing of a server. + * + * @author Adrian Cole + * @see + */ +public class Server { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + protected String id; + protected String hostname; + protected String datacenter; + protected String platform; + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder hostname(String hostname) { + this.hostname = hostname; + return this; + } + + public Builder datacenter(String datacenter) { + this.datacenter = datacenter; + return this; + } + + public Builder platform(String platform) { + this.platform = platform; + return this; + } + + public Server build() { + return new Server(id, hostname, datacenter, platform); + } + + public Builder fromServer(Server in) { + return datacenter(in.getDatacenter()).platform(in.getPlatform()).hostname(in.getHostname()).id(in.getId()); + } + } + + @SerializedName("serverid") + protected final String id; + protected final String hostname; + protected final String datacenter; + protected final String platform; + + public Server(String id, String hostname, String datacenter, String platform) { + this.id = checkNotNull(id, "id"); + this.hostname = checkNotNull(hostname, "hostname"); + this.datacenter = checkNotNull(datacenter, "datacenter"); + this.platform = checkNotNull(platform, "platform"); + } + + /** + * @return the generated id of the server + */ + public String getId() { + return id; + } + + /** + * @return the hostname of the server + */ + public String getHostname() { + return hostname; + } + + /** + * @return platform running the server (ex. {@code OpenVZ}) + */ + public String getPlatform() { + return platform; + } + + /** + * @return the datacenter the server exists in (ex. {@code Falkenberg}) + */ + public String getDatacenter() { + return datacenter; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((datacenter == null) ? 0 : datacenter.hashCode()); + result = prime * result + ((hostname == null) ? 0 : hostname.hashCode()); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((platform == null) ? 0 : platform.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; + Server other = (Server) obj; + if (datacenter == null) { + if (other.datacenter != null) + return false; + } else if (!datacenter.equals(other.datacenter)) + return false; + if (hostname == null) { + if (other.hostname != null) + return false; + } else if (!hostname.equals(other.hostname)) + return false; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (platform == null) { + if (other.platform != null) + return false; + } else if (!platform.equals(other.platform)) + return false; + return true; + } + + @Override + public String toString() { + return String.format("[id=%s, hostname=%s, datacenter=%s, platform=%s]", id, hostname, datacenter, platform); + } + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/ServerDetails.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/ServerDetails.java new file mode 100644 index 0000000000..9ee8846604 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/ServerDetails.java @@ -0,0 +1,150 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.gson.annotations.SerializedName; + +/** + * Detailed information about a server such as cpuCores, hardware configuration + * (cpu, memory and disk), ip adresses, cost, transfer, os and more. + * + * @author Adrian Cole + * @see + */ +public class ServerDetails extends Server { + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends Server.Builder { + private String description; + private int cpuCores; + private int memory; + private int disk; + + public Builder description(String description) { + this.description = description; + return this; + } + + public Builder cpuCores(int cpuCores) { + this.cpuCores = cpuCores; + return this; + } + + public Builder memory(int memory) { + this.memory = memory; + return this; + } + + public Builder disk(int disk) { + this.disk = disk; + return this; + } + + public ServerDetails build() { + return new ServerDetails(id, hostname, datacenter, platform, description, cpuCores, memory, disk); + } + + public Builder fromServerDetails(ServerDetails in) { + return fromServer(in).memory(in.getMemory()).disk(in.getDisk()).cpuCores(in.getCpuCores()) + .description(in.getDescription()); + } + + @Override + public Builder id(String id) { + return Builder.class.cast(super.id(id)); + } + + @Override + public Builder hostname(String hostname) { + return Builder.class.cast(super.hostname(hostname)); + } + + @Override + public Builder datacenter(String datacenter) { + return Builder.class.cast(super.datacenter(datacenter)); + } + + @Override + public Builder platform(String platform) { + return Builder.class.cast(super.platform(platform)); + } + + @Override + public Builder fromServer(Server in) { + return Builder.class.cast(super.fromServer(in)); + } + } + + private final String description; + @SerializedName("cpucores") + private final int cpuCores; + private final int memory; + private final int disk; + + public ServerDetails(String id, String hostname, String datacenter, String platform, String description, + int cpuCores, int memory, int disk) { + super(id, hostname, datacenter, platform); + this.description = checkNotNull(description, "description"); + this.cpuCores = cpuCores; + this.memory = memory; + this.disk = disk; + } + + /** + * @return the user-specified description of the server + */ + public String getDescription() { + return description; + } + + /** + * @return number of cores on the server + */ + public int getCpuCores() { + return cpuCores; + } + + /** + * @return the disk of the server in GB + */ + public int getDisk() { + return disk; + } + + /** + * @return the memory of the server in MB + */ + public int getMemory() { + return memory; + } + + @Override + public String toString() { + return String.format( + "[id=%s, hostname=%s, datacenter=%s, platform=%s, description=%s, cpuCores=%s, memory=%s, disk=%s]", id, + hostname, datacenter, platform, description, cpuCores, memory, disk); + } + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClient.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClient.java new file mode 100644 index 0000000000..4629e1ca0e --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClient.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.openstack.nova.v1_1.features; + +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.openstack.filters.AuthenticateRequest; +import org.jclouds.openstack.nova.v1_1.domain.Server; +import org.jclouds.openstack.nova.v1_1.domain.ServerDetails; +import org.jclouds.rest.annotations.ExceptionParser; +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 com.google.common.util.concurrent.ListenableFuture; + +/** + * Provides asynchronous access to Server via their REST API. + *

+ * + * @see ServerClient + * @see + * @author Adrian Cole + */ +@RequestFilters(AuthenticateRequest.class) +public interface ServerAsyncClient { + + /** + * @see ServerClient#listServers + */ + @GET + @SelectJson("servers") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/servers") + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listServers(); + + /** + * @see ServerClient#getServerDetails + */ + @GET + @SelectJson("server") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/servers/{id}") + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getServerDetails(@PathParam("id") String id); + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerClient.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerClient.java new file mode 100644 index 0000000000..9daacff4f3 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerClient.java @@ -0,0 +1,58 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.features; + +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; +import org.jclouds.openstack.nova.v1_1.domain.Server; +import org.jclouds.openstack.nova.v1_1.domain.ServerDetails; + +/** + * Provides synchronous access to Server. + *

+ * + * @see ServerAsyncClient + * @see + * @author Adrian Cole + */ +@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS) +public interface ServerClient { + + /** + * Get a list of all servers on this account. + * + * @return an account's associated server objects. + */ + Set listServers(); + + /** + * Get detailed information about a server such as hostname, hardware + * configuration (cpu, memory and disk), ip adresses, cost, transfer, os and + * more. + * + * @param id + * id of the server + * @return server or null if not found + */ + ServerDetails getServerDetails(String id); + + +} diff --git a/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/handlers/NovaErrorHandler.java b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/handlers/NovaErrorHandler.java new file mode 100644 index 0000000000..943a5dad47 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/handlers/NovaErrorHandler.java @@ -0,0 +1,90 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.handlers; + +import java.io.IOException; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceNotFoundException; +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 NovaErrorHandler implements HttpErrorHandler { + + 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; + case 500: + if (message != null && message.indexOf("Unable to determine package for") != -1) { + exception = new ResourceNotFoundException(message, exception); + } + } + } 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-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClientTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClientTest.java new file mode 100644 index 0000000000..69cd52b395 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClientTest.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.openstack.nova.v1_1; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +import org.jclouds.http.HttpRequest; +import org.jclouds.openstack.nova.v1_1.features.BaseNovaAsyncClientTest; +import org.jclouds.rest.internal.RestAnnotationProcessor; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.inject.TypeLiteral; + +/** + * Tests behavior of {@code NovaAsyncClient} + * + * @author Adrian Cole + */ +// NOTE:without testName, this will not call @Before* and fail w/NPE during +// surefire +@Test(groups = "unit", testName = "NovaAsyncClientTest") +public class NovaAsyncClientTest extends BaseNovaAsyncClientTest { + + private NovaAsyncClient asyncClient; + private NovaClient syncClient; + + public void testSync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException { + assert syncClient.getServerClient() != null; + } + + public void testAsync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException { + assert asyncClient.getServerClient() != null; + } + + @Override + protected TypeLiteral> createTypeLiteral() { + return new TypeLiteral>() { + }; + } + + @BeforeClass + @Override + protected void setupFactory() throws IOException { + super.setupFactory(); + asyncClient = injector.getInstance(NovaAsyncClient.class); + syncClient = injector.getInstance(NovaClient.class); + } + + @Override + protected void checkFilters(HttpRequest request) { + + } +} diff --git a/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/NovaErrorHandlerTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/NovaErrorHandlerTest.java new file mode 100644 index 0000000000..94516d7afc --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/NovaErrorHandlerTest.java @@ -0,0 +1,117 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1; + +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.reportMatcher; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; + +import java.net.URI; + +import org.easymock.IArgumentMatcher; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.io.Payloads; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceNotFoundException; +import org.jclouds.openstack.nova.v1_1.handlers.NovaErrorHandler; +import org.jclouds.util.Strings2; +import org.testng.annotations.Test; + +import com.google.inject.Guice; + +/** + * + * @author Adrian Cole + */ +@Test(groups = { "unit" }) +public class NovaErrorHandlerTest { + + @Test + public void test500MakesResourceNotFoundExceptionOnUnableToDeterminePackage() { + assertCodeMakes( + "GET", + URI.create("https://api.openstack.nova.v1_1.com/foo"), + 500, + "", + "{\"error\":\"Unable to determine package for 'node2102835255.me.org'.\"}", + ResourceNotFoundException.class); + } + + @Test + public void test401MakesAuthorizationException() { + assertCodeMakes("GET", URI.create("https://api.openstack.nova.v1_1.com/foo"), 401, "", "Unauthorized", + AuthorizationException.class); + } + + @Test + public void test404MakesResourceNotFoundException() { + assertCodeMakes("GET", URI.create("https://api.openstack.nova.v1_1.com/foo"), 404, "", "Not Found", + ResourceNotFoundException.class); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content, + Class expected) { + assertCodeMakes(method, uri, statusCode, message, "text/xml", content, expected); + } + + private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType, + String content, Class expected) { + + NovaErrorHandler function = Guice.createInjector().getInstance(NovaErrorHandler.class); + + HttpCommand command = createMock(HttpCommand.class); + HttpRequest request = new HttpRequest(method, uri); + HttpResponse response = new HttpResponse(statusCode, message, Payloads.newInputStreamPayload(Strings2 + .toInputStream(content))); + response.getPayload().getContentMetadata().setContentType(contentType); + + expect(command.getCurrentRequest()).andReturn(request).atLeastOnce(); + command.setException(classEq(expected)); + + replay(command); + + function.handleError(command, response); + + verify(command); + } + + public static Exception classEq(final Class in) { + reportMatcher(new IArgumentMatcher() { + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("classEq("); + buffer.append(in); + buffer.append(")"); + } + + @Override + public boolean matches(Object arg) { + return arg.getClass() == in; + } + + }); + return null; + } + +} diff --git a/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/BaseNovaAsyncClientTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/BaseNovaAsyncClientTest.java new file mode 100644 index 0000000000..0a1de0f22a --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/BaseNovaAsyncClientTest.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.openstack.nova.v1_1.features; + +import static org.testng.Assert.assertEquals; + +import java.util.Properties; + +import org.jclouds.http.HttpRequest; +import org.jclouds.openstack.filters.AuthenticateRequest; +import org.jclouds.openstack.nova.v1_1.NovaAsyncClient; +import org.jclouds.openstack.nova.v1_1.NovaClient; +import org.jclouds.rest.RestClientTest; +import org.jclouds.rest.RestContextFactory; +import org.jclouds.rest.RestContextSpec; + +/** + * @author Adrian Cole + */ +public abstract class BaseNovaAsyncClientTest extends RestClientTest { + + @Override + protected void checkFilters(HttpRequest request) { + assertEquals(request.getFilters().size(), 1); + assertEquals(request.getFilters().get(0).getClass(), AuthenticateRequest.class); + } + + @Override + public RestContextSpec createContextSpec() { + Properties props = new Properties(); + return new RestContextFactory().createContextSpec("openstack-nova", "accountId", "accessKey", props); + } + +} diff --git a/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/BaseNovaClientLiveTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/BaseNovaClientLiveTest.java new file mode 100644 index 0000000000..b83c4efbf3 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/BaseNovaClientLiveTest.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.v1_1.features; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.openstack.nova.v1_1.NovaAsyncClient; +import org.jclouds.openstack.nova.v1_1.NovaClient; +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.rest.RestContext; +import org.jclouds.rest.RestContextFactory; +import org.jclouds.sshj.config.SshjSshClientModule; +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 NovaClient} + * + * @author Adrian Cole + */ +@Test(groups = "live") +public class BaseNovaClientLiveTest { + + protected RestContext context; + + @BeforeGroups(groups = { "live" }) + public void setupClient() { + String identity = checkNotNull(System.getProperty("test.openstack.nova.v1_1.identity"), "test.openstack.nova.v1_1.identity"); + String credential = checkNotNull(System.getProperty("test.openstack.nova.v1_1.credential"), "test.openstack.nova.v1_1.credential"); + + context = new RestContextFactory().createContext("openstack-nova", identity, credential, + ImmutableSet. of(new Log4JLoggingModule(), new SshjSshClientModule())); + + } + + @AfterGroups(groups = "live") + protected void tearDown() { + if (context != null) + context.close(); + } + +} diff --git a/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClientTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClientTest.java new file mode 100644 index 0000000000..b7c18c3798 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClientTest.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.openstack.nova.v1_1.features; + +import java.io.IOException; +import java.lang.reflect.Method; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.functions.ParseFirstJsonValueNamed; +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 + */ +@Test(groups = "unit", testName = "ServerAsyncClientTest") +public class ServerAsyncClientTest extends BaseNovaAsyncClientTest { + + public void testListServers() throws SecurityException, NoSuchMethodException, IOException { + Method method = ServerAsyncClient.class.getMethod("listServers"); + HttpRequest httpRequest = processor.createRequest(method); + + assertRequestLineEquals(httpRequest, "GET http://localhost:8774/v1.1/accountId/servers HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseFirstJsonValueNamed.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testGetServer() throws SecurityException, NoSuchMethodException, IOException { + Method method = ServerAsyncClient.class.getMethod("getServerDetails", String.class); + HttpRequest httpRequest = processor.createRequest(method, "abcd"); + + assertRequestLineEquals(httpRequest, + "GET http://localhost:8774/v1.1/accountId/servers/abcd HTTP/1.1"); + assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null, null, false); + + assertResponseParserClassEquals(method, httpRequest, ParseFirstJsonValueNamed.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + @Override + protected TypeLiteral> createTypeLiteral() { + return new TypeLiteral>() { + }; + } +} diff --git a/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/ServerClientLiveTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/ServerClientLiveTest.java new file mode 100644 index 0000000000..b5fc287f9e --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/ServerClientLiveTest.java @@ -0,0 +1,68 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Set; + +import org.jclouds.openstack.nova.v1_1.domain.Server; +import org.jclouds.openstack.nova.v1_1.domain.ServerDetails; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code ServerClient} + * + * @author Adrian Cole + */ +@Test(groups = "live", testName = "ServerClientLiveTest") +public class ServerClientLiveTest extends BaseNovaClientLiveTest { + + @BeforeGroups(groups = {"live"}) + public void setupClient() { + super.setupClient(); + client = context.getApi().getServerClient(); + } + + private ServerClient client; + + @Test + public void testListServers() throws Exception { + Set response = client.listServers(); + assert null != response; + assertTrue(response.size() >= 0); + for (Server server : response) { + ServerDetails newDetails = client.getServerDetails(server.getId()); + assertEquals(newDetails.getId(), server.getId()); + assertEquals(newDetails.getHostname(), server.getHostname()); + assertEquals(newDetails.getPlatform(), server.getPlatform()); + assertEquals(newDetails.getDatacenter(), server.getDatacenter()); + checkServer(newDetails); + } + } + + private void checkServer(ServerDetails server) { + // description can be null + assert server.getCpuCores() > 0 : server; + assert server.getDisk() > 0 : server; + assert server.getMemory() > 0 : server; + } +} diff --git a/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsTest.java new file mode 100644 index 0000000000..88e27b5aa0 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerDetailsTest.java @@ -0,0 +1,58 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.parse; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.openstack.nova.v1_1.config.NovaParserModule; +import org.jclouds.openstack.nova.v1_1.domain.ServerDetails; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ParseServerDetailsTest") +public class ParseServerDetailsTest extends BaseItemParserTest { + + @Override + public String resource() { + return "/server.json"; + } + + @Override + @SelectJson("server") + @Consumes(MediaType.APPLICATION_JSON) + public ServerDetails expected() { + return ServerDetails.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ") + .description("description").cpuCores(1).memory(128).disk(5).build(); + } + + protected Injector injector() { + return Guice.createInjector(new NovaParserModule(), new GsonModule()); + } + +} diff --git a/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerListTest.java b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerListTest.java new file mode 100644 index 0000000000..cf9d300b61 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/parse/ParseServerListTest.java @@ -0,0 +1,61 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.parse; + +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.json.BaseSetParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.openstack.nova.v1_1.config.NovaParserModule; +import org.jclouds.openstack.nova.v1_1.domain.Server; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "ParseServerListTest") +public class ParseServerListTest extends BaseSetParserTest { + + @Override + public String resource() { + return "/server_list.json"; + } + + @Override + @SelectJson("servers") + @Consumes(MediaType.APPLICATION_JSON) + public Set expected() { + return ImmutableSet.of(Server.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg") + .platform("OpenVZ").build()); + } + + protected Injector injector() { + return Guice.createInjector(new NovaParserModule(), new GsonModule()); + } + +} diff --git a/sandbox-apis/openstack-nova/src/test/resources/log4j.xml b/sandbox-apis/openstack-nova/src/test/resources/log4j.xml new file mode 100644 index 0000000000..63810d3ca0 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/resources/log4j.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandbox-apis/openstack-nova/src/test/resources/server.json b/sandbox-apis/openstack-nova/src/test/resources/server.json new file mode 100644 index 0000000000..83872c0fa8 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/resources/server.json @@ -0,0 +1,54 @@ +{ + "server": { + "status": "REBOOT", + "updated": "2011-12-06T22:37:44Z", + "hostId": "3852db942cbeb5e840d759de11bdef403e2a0149c66f06a5d7caa61e", + "user_id": "dev_41247879706381", + "name": "jd-test-tiny", + "links": [ + { + "href": "http://se1.devex.me:8774/v1.1/dev_16767499955063/servers/804", + "rel": "self" + }, + { + "href": "http://se1.devex.me:8774/dev_16767499955063/servers/804", + "rel": "bookmark" + } + ], + "addresses": { + "novanet_7": [ + { + "version": 4, + "addr": "10.0.0.229" + } + ] + }, + "tenant_id": "dev_16767499955063", + "image": { + "id": "146", + "links": [ + { + "href": "http://se1.devex.me:8774/dev_16767499955063/images/146", + "rel": "bookmark" + } + ] + }, + "created": "2011-12-02T16:04:54Z", + "uuid": "0bab236f-f5c4-46ef-93c2-a8e2bcfffff6", + "accessIPv4": "", + "accessIPv6": "", + "key_name": null, + "flavor": { + "id": "1", + "links": [ + { + "href": "http://se1.devex.me:8774/dev_16767499955063/flavors/1", + "rel": "bookmark" + } + ] + }, + "config_drive": "", + "id": 804, + "metadata": {} + } +} \ No newline at end of file diff --git a/sandbox-apis/openstack-nova/src/test/resources/server_list.json b/sandbox-apis/openstack-nova/src/test/resources/server_list.json new file mode 100644 index 0000000000..e6a7eec520 --- /dev/null +++ b/sandbox-apis/openstack-nova/src/test/resources/server_list.json @@ -0,0 +1,64 @@ +{ + "servers": [ + { + "uuid": "0bab236f-f5c4-46ef-93c2-a8e2bcfffff6", + "name": "jd-test-tiny", + "links": [ + { + "href": "http://se1.devex.me:8774/v1.1/dev_16767499955063/servers/804", + "rel": "self" + }, + { + "href": "http://se1.devex.me:8774/dev_16767499955063/servers/804", + "rel": "bookmark" + } + ], + "id": 804 + }, + { + "uuid": "488eac65-84ab-4f10-b2a4-555c23613428", + "name": "rgtest2", + "links": [ + { + "href": "http://se1.devex.me:8774/v1.1/dev_16767499955063/servers/528", + "rel": "self" + }, + { + "href": "http://se1.devex.me:8774/dev_16767499955063/servers/528", + "rel": "bookmark" + } + ], + "id": 528 + }, + { + "uuid": "df891742-4ecb-4f9f-b206-b2a4d821a100", + "name": "rgtest", + "links": [ + { + "href": "http://se1.devex.me:8774/v1.1/dev_16767499955063/servers/507", + "rel": "self" + }, + { + "href": "http://se1.devex.me:8774/dev_16767499955063/servers/507", + "rel": "bookmark" + } + ], + "id": 507 + }, + { + "uuid": "42cded93-1ade-4da2-b39f-70e6577c2b82", + "name": "fog_hprgmac.local_1320358100_server", + "links": [ + { + "href": "http://se1.devex.me:8774/v1.1/dev_16767499955063/servers/430", + "rel": "self" + }, + { + "href": "http://se1.devex.me:8774/dev_16767499955063/servers/430", + "rel": "bookmark" + } + ], + "id": 430 + } + ] +}