From 48c0794b09068a538b9d2429af5280b63db9c6b3 Mon Sep 17 00:00:00 2001 From: Arvind Nadendla Date: Fri, 17 Jul 2015 19:38:11 -0700 Subject: [PATCH] add os-hypervisors extension for openstack-nova --- apis/openstack-nova/pom.xml | 5 + .../jclouds/openstack/nova/v2_0/NovaApi.java | 21 +- .../nova/v2_0/config/NovaHttpApiModule.java | 28 +-- .../v2_0/domain/regionscoped/Hypervisor.java | 38 ++++ .../regionscoped/HypervisorDetails.java | 78 ++++++++ .../v2_0/extensions/ExtensionNamespaces.java | 4 + .../nova/v2_0/extensions/HypervisorApi.java | 59 ++++++ .../extensions/HypervisorApiLiveTest.java | 72 +++++++ .../extensions/HypervisorApiMockTest.java | 187 ++++++++++++++++++ .../src/test/resources/access.json | 14 ++ .../test/resources/extension_list_full.json | 8 + .../test/resources/hypervisor_details.json | 40 ++++ .../src/test/resources/hypervisor_list.json | 12 ++ 13 files changed, 547 insertions(+), 19 deletions(-) create mode 100644 apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/Hypervisor.java create mode 100644 apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/HypervisorDetails.java create mode 100644 apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApi.java create mode 100644 apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiLiveTest.java create mode 100644 apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiMockTest.java create mode 100644 apis/openstack-nova/src/test/resources/hypervisor_details.json create mode 100644 apis/openstack-nova/src/test/resources/hypervisor_list.json diff --git a/apis/openstack-nova/pom.xml b/apis/openstack-nova/pom.xml index 1c12743e56..4e63a9f091 100644 --- a/apis/openstack-nova/pom.xml +++ b/apis/openstack-nova/pom.xml @@ -124,6 +124,11 @@ auto-service true + + com.google.auto.value + auto-value + provided + diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java index 3197540d82..838ef38f4f 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java @@ -16,9 +16,8 @@ */ package org.jclouds.openstack.nova.v2_0; -import java.io.Closeable; -import java.util.Set; - +import com.google.common.base.Optional; +import com.google.inject.Provides; import org.jclouds.location.Region; import org.jclouds.location.functions.RegionToEndpoint; import org.jclouds.openstack.nova.v2_0.extensions.AttachInterfaceApi; @@ -29,6 +28,7 @@ import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi; import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPPoolApi; import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationApi; import org.jclouds.openstack.nova.v2_0.extensions.HostAggregateApi; +import org.jclouds.openstack.nova.v2_0.extensions.HypervisorApi; import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi; import org.jclouds.openstack.nova.v2_0.extensions.QuotaApi; import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi; @@ -46,8 +46,8 @@ import org.jclouds.openstack.v2_0.features.ExtensionApi; import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.EndpointParam; -import com.google.common.base.Optional; -import com.google.inject.Provides; +import java.io.Closeable; +import java.util.Set; /** * Provides access to the OpenStack Compute (Nova) v2 API. @@ -219,6 +219,17 @@ public interface NovaApi extends Closeable { Optional getQuotaApi( @EndpointParam(parser = RegionToEndpoint.class) String region); + /** + * Provides access to Hypervisor features. + * + *

NOTE

+ * This API is an extension that may or may not be present in your OpenStack cloud. Use the Optional return type + * to determine if it is present. + */ + @Delegate + Optional getHypervisorApi( + @EndpointParam(parser = RegionToEndpoint.class) String region); + /** * Provides access to Volume features. * diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java index 830c7b89fa..4a74cf7e6a 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java @@ -16,15 +16,11 @@ */ package org.jclouds.openstack.nova.v2_0.config; -import static org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule.aliasBinder; - -import java.net.URI; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import javax.inject.Provider; -import javax.inject.Singleton; - +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.inject.Provides; +import com.google.inject.multibindings.MapBinder; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.Redirection; @@ -38,11 +34,13 @@ import org.jclouds.rest.ConfiguresHttpApi; import org.jclouds.rest.config.HttpApiModule; import org.jclouds.rest.functions.ImplicitOptionalConverter; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.inject.Provides; -import com.google.inject.multibindings.MapBinder; +import javax.inject.Provider; +import javax.inject.Singleton; +import java.net.URI; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule.aliasBinder; /** * Configures the Nova connection. @@ -96,6 +94,8 @@ public class NovaHttpApiModule extends HttpApiModule { URI.create("http://docs.openstack.org/compute/ext/os-volume-attachment-update/api/v2")); aliases.addBinding(URI.create(ExtensionNamespaces.ATTACH_INTERFACES)).toInstance( URI.create("http://docs.openstack.org/compute/ext/interfaces/api/v1.1")); + aliases.addBinding(URI.create(ExtensionNamespaces.HYPERVISORS)).toInstance( + URI.create("http://docs.openstack.org/compute/ext/hypervisors/api/v1.1")); } @Provides diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/Hypervisor.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/Hypervisor.java new file mode 100644 index 0000000000..c2712b35e3 --- /dev/null +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/Hypervisor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.domain.regionscoped; + +import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * Hypervisor which shows id and name + */ +@AutoValue +public abstract class Hypervisor { + + public abstract String getId(); + + @Nullable + public abstract String getName(); + + @SerializedNames({"id" , "hypervisor_hostname"}) + private static Hypervisor create(String id, String name) { + return new AutoValue_Hypervisor(id, name); + } +} diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/HypervisorDetails.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/HypervisorDetails.java new file mode 100644 index 0000000000..c67c353cf6 --- /dev/null +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/regionscoped/HypervisorDetails.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.domain.regionscoped; + +import com.google.auto.value.AutoValue; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +/** + * Hypervisor which shows id, name and other details + */ +@AutoValue +public abstract class HypervisorDetails { + + public abstract String getId(); + + @Nullable + public abstract String getName(); + + @Nullable + public abstract Integer getCurrentWorkload(); + + @Nullable + public abstract Integer getDiskAvailableLeast(); + + @Nullable + public abstract Integer getFreeDiskGb(); + + @Nullable + public abstract Integer getFreeRamMb(); + + public abstract String getHypervisorType(); + + public abstract int getHypervisorVersion(); + + public abstract int getLocalGb(); + + public abstract int getLocalGbUsed(); + + public abstract int getMemoryMb(); + + public abstract int getMemoryMbUsed(); + + @Nullable + public abstract Integer getRunningVms(); + + public abstract int getVcpus(); + + public abstract int getVcpusUsed(); + + @Nullable + public abstract String getCpuInfo(); + + @SerializedNames({ "id", "hypervisor_hostname", "current_workload", "disk_available_least", "free_disk_gb", "free_ram_mb", "hypervisor_type", + "hypervisor_version", "local_gb", "local_gb_used", "memory_mb", "memory_mb_used", "running_vms", "vcpus", "vcpus_used", + "cpu_info" }) + private static HypervisorDetails create(String id, String name, int currentWorkload, int diskAvailableLeast, int freeDiskGb, int freeRamMb, + String hypervisorType, int hypervisorVersion, int localGb, int localGbUsed, int memoryMb, int memoryMbUsed, int runningVms, + int vcpus, int vcpusUsed, String cpuInfo) { + return new AutoValue_HypervisorDetails(id, name, currentWorkload, diskAvailableLeast, freeDiskGb, freeRamMb, hypervisorType, hypervisorVersion, + localGb, localGbUsed, memoryMb, memoryMbUsed, runningVms, vcpus, vcpusUsed, cpuInfo); + } + +} diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java index 888ab7a6ba..84be0284da 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ExtensionNamespaces.java @@ -121,6 +121,10 @@ public final class ExtensionNamespaces { * Attach interfaces extension */ public static final String ATTACH_INTERFACES = "http://docs.openstack.org/compute/ext/interfaces/api/v1.1"; + /** + * Hypervisor support + */ + public static final String HYPERVISORS = "http://docs.openstack.org/compute/ext/hypervisors/api/v1.1"; private ExtensionNamespaces() { throw new AssertionError("intentionally unimplemented"); diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApi.java new file mode 100644 index 0000000000..17feddaa6d --- /dev/null +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApi.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.extensions; + +import com.google.common.annotations.Beta; +import com.google.common.collect.FluentIterable; +import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404; +import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; +import org.jclouds.openstack.nova.v2_0.domain.regionscoped.Hypervisor; +import org.jclouds.openstack.nova.v2_0.domain.regionscoped.HypervisorDetails; +import org.jclouds.openstack.v2_0.ServiceType; +import org.jclouds.openstack.v2_0.services.Extension; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +/** + * Provides access to the OpenStack Compute (Nova) Hypervisor Extension API. + */ +@Beta +@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.HYPERVISORS) +@RequestFilters(AuthenticateRequest.class) +@Consumes(MediaType.APPLICATION_JSON) +@Path("/os-hypervisors") +public interface HypervisorApi { + + @Named("hypervisors:list") + @GET + @SelectJson("hypervisors") + @Fallback(EmptyFluentIterableOnNotFoundOr404.class) + FluentIterable list(); + + @Named("hypervisors:list") + @GET + @Path("/detail") + @SelectJson("hypervisors") + @Fallback(EmptyFluentIterableOnNotFoundOr404.class) + FluentIterable listInDetail(); +} diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiLiveTest.java new file mode 100644 index 0000000000..c2cc0773e7 --- /dev/null +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiLiveTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.extensions; + +import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; +import org.jclouds.openstack.nova.v2_0.domain.regionscoped.Hypervisor; +import org.jclouds.openstack.nova.v2_0.domain.regionscoped.HypervisorDetails; +import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; + +@Test(groups = "live", testName = "HypervisorApiLiveTest") +public class HypervisorApiLiveTest extends BaseNovaApiLiveTest { + + @Test + public void testList() throws Exception { + + Optional hypervisorApi = api.getHypervisorApi("RegionOne"); + if (hypervisorApi.isPresent()) { + FluentIterable hypervisors = hypervisorApi.get().list(); + + for (Hypervisor hypervisor : hypervisors) { + assertNotNull(hypervisor.getName()); + assertNotNull(hypervisor.getId(), "hypervisor: " + hypervisor.getName() + " has invalid id"); + } + } + } + + @Test + public void testListInDetail() throws Exception { + + Optional hypervisorApi = api.getHypervisorApi("RegionOne"); + if (hypervisorApi.isPresent()) { + FluentIterable hypervisors = hypervisorApi.get().listInDetail(); + + for (HypervisorDetails hypervisorDetails : hypervisors) { + assertNotNull(hypervisorDetails.getId(), "Expected hypervisor id"); + assertNotNull(hypervisorDetails.getName(), "Expected hypervisor name"); + assertNotNull(hypervisorDetails.getCurrentWorkload(), "Expected CurrentWorkload"); + assertNotNull(hypervisorDetails.getDiskAvailableLeast(), "Expected Disk Available Least"); + assertNotNull(hypervisorDetails.getFreeDiskGb(), "Expected Free Disk Gb"); + assertNotNull(hypervisorDetails.getFreeRamMb(), "Expected Free Ram Mb"); + assertNotNull(hypervisorDetails.getHypervisorType(), "Expected Hypervisor Type"); + assertNotNull(hypervisorDetails.getHypervisorVersion(), "Expected Hypervisor Version"); + assertNotNull(hypervisorDetails.getLocalGb(), "Expected Local Gb"); + assertNotNull(hypervisorDetails.getLocalGbUsed(), "Expected Local Gb Used"); + assertNotNull(hypervisorDetails.getMemoryMb(), "Expected Memory Mb "); + assertNotNull(hypervisorDetails.getMemoryMbUsed(), "Expected Memory Mb Used"); + assertNotNull(hypervisorDetails.getRunningVms(), "Expected Running Vms"); + assertNotNull(hypervisorDetails.getVcpus(), "Expected Vcpus"); + assertNotNull(hypervisorDetails.getVcpusUsed(), "Expected Vcpus Used"); + assertNotNull(hypervisorDetails.getCpuInfo(), "Eexpected Cpu Info"); + } + } + } +} diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiMockTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiMockTest.java new file mode 100644 index 0000000000..b09ddd711f --- /dev/null +++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HypervisorApiMockTest.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.v2_0.extensions; + +import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import org.jclouds.openstack.nova.v2_0.NovaApi; +import org.jclouds.openstack.nova.v2_0.domain.regionscoped.Hypervisor; +import org.jclouds.openstack.nova.v2_0.domain.regionscoped.HypervisorDetails; +import org.jclouds.openstack.v2_0.internal.BaseOpenStackMockTest; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +@Test(groups = "unit", testName = "HypervisorApiMockTest") +public class HypervisorApiMockTest extends BaseOpenStackMockTest { + + private static Map servers = new ConcurrentHashMap(); + + @BeforeMethod + public void setupMockServer(Method method) throws IOException { + servers.put(method.getName(), mockOpenStackServer()); + servers.get(method.getName()).enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + } + + @AfterMethod + public void tearDownMockServer(Method method) throws IOException { + servers.get(method.getName()).shutdown(); + } + + public void testWhenNamespaceInExtensionsListHypervisorPresent(Method method) throws Exception { + MockWebServer server = servers.get(method.getName()); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list_full.json")))); + + NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova"); + assertEquals(novaApi.getConfiguredRegions(), ImmutableSet.of("RegionOne", "RegionTwo", "RegionThree")); + + Optional hypervisorApi = novaApi.getHypervisorApi("RegionOne"); + + assertTrue(hypervisorApi.isPresent()); + + assertRequests(server, 2, null); + } + + public void testWhenNamespaceNotInExtensionsListHypervisorPresent(Method method) throws Exception { + MockWebServer server = servers.get(method.getName()); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list.json")))); + + NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova"); + assertEquals(novaApi.getConfiguredRegions(), ImmutableSet.of("RegionOne", "RegionTwo", "RegionThree")); + + Optional hypervisorApi = novaApi.getHypervisorApi("RegionOne"); + + assertFalse(hypervisorApi.isPresent()); + + assertRequests(server, 2, null); + } + + public void testListHypervisor(Method method) throws Exception { + MockWebServer server = servers.get(method.getName()); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list_full.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/hypervisor_list.json")))); + + NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova"); + assertEquals(novaApi.getConfiguredRegions(), ImmutableSet.of("RegionOne", "RegionTwo", "RegionThree")); + + FluentIterable hypervisors = novaApi.getHypervisorApi("RegionOne").get().list(); + + Optional hypervisor = hypervisors.first(); + + assertTrue(hypervisor.isPresent(), "Couldn't find hypervisor"); + assertEquals(hypervisor.get().getId(), "1", "Expected hypervisor id to be 1 but it was: " + hypervisor.get().getId()); + assertEquals(hypervisor.get().getName(), "os-compute1", "Expected hypervisor name to be os-compute1 but it was: " + hypervisor.get().getName()); + + assertRequests(server, 3, "/os-hypervisors"); + } + + public void testListHypervisorWhenResponseIs404(Method method) throws Exception { + MockWebServer server = servers.get(method.getName()); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list_full.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova"); + assertEquals(novaApi.getConfiguredRegions(), ImmutableSet.of("RegionOne", "RegionTwo", "RegionThree")); + + assertTrue(novaApi.getHypervisorApi("RegionOne").get().list().isEmpty()); + + assertRequests(server, 3, "/os-hypervisors"); + } + + public void testListInDetail(Method method) throws Exception { + MockWebServer server = servers.get(method.getName()); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list_full.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/hypervisor_details.json")))); + + NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova"); + assertEquals(novaApi.getConfiguredRegions(), ImmutableSet.of("RegionOne", "RegionTwo", "RegionThree")); + + FluentIterable hypervisors = novaApi.getHypervisorApi("RegionOne").get().listInDetail(); + + Optional hypervisorDetailsOptional = hypervisors.first(); + + assertTrue(hypervisorDetailsOptional.isPresent(), "Couldn't find Hypervisor Details"); + HypervisorDetails hypervisorDetails = hypervisorDetailsOptional.get(); + assertEquals(hypervisorDetails.getId(), "1", "Expected hypervisor id to be 1 but it was: " + hypervisorDetails.getId()); + assertEquals(hypervisorDetails.getName(), "os-compute1", + "Expected hypervisor name to be os-compute1 but it was: " + hypervisorDetails.getName()); + assertEquals(hypervisorDetails.getCurrentWorkload(), Integer.valueOf(0), + "Expected CurrentWorkload to be 0 but it was: " + hypervisorDetails.getCurrentWorkload()); + assertEquals(hypervisorDetails.getDiskAvailableLeast(), Integer.valueOf(131), + "Expected Disk Available Least to be 131 but it was: " + hypervisorDetails.getDiskAvailableLeast()); + assertEquals(hypervisorDetails.getFreeDiskGb(), Integer.valueOf(144), + "Expected Free Disk Gb to be 144 but it was: " + hypervisorDetails.getFreeDiskGb()); + assertEquals(hypervisorDetails.getFreeRamMb(), Integer.valueOf(12911), + "Expected Free Ram Mb to be 12911 but it was: " + hypervisorDetails.getFreeRamMb()); + assertEquals(hypervisorDetails.getHypervisorType(), "QEMU", + "Expected Hypervisor Type to be QEMU but it was: " + hypervisorDetails.getHypervisorType()); + assertEquals(hypervisorDetails.getHypervisorVersion(), 2000000, + "Expected Hypervisor Version to be 2000000 but it was: " + hypervisorDetails.getHypervisorVersion()); + assertEquals(hypervisorDetails.getLocalGb(), 195, "Expected Local Gb to be 195 but it was: " + hypervisorDetails.getLocalGb()); + assertEquals(hypervisorDetails.getLocalGbUsed(), 51, "Expected Local Gb Used to be 51 but it was: " + hypervisorDetails.getLocalGbUsed()); + assertEquals(hypervisorDetails.getMemoryMb(), 20079, "Expected Memory Mb to be 20079 but it was: " + hypervisorDetails.getMemoryMb()); + assertEquals(hypervisorDetails.getMemoryMbUsed(), 7168, + "Expected Memory Mb Used to be 7168 but it was: " + hypervisorDetails.getMemoryMbUsed()); + assertEquals(hypervisorDetails.getRunningVms(), Integer.valueOf(2), + "Expected Running Vms to be 2 but it was: " + hypervisorDetails.getRunningVms()); + assertEquals(hypervisorDetails.getVcpus(), 16, "Expected Vcpus to be 16 but it was: " + hypervisorDetails.getVcpus()); + assertEquals(hypervisorDetails.getVcpusUsed(), 5, "Expected Vcpus Used to be 5 but it was: " + hypervisorDetails.getVcpusUsed()); + assertEquals(hypervisorDetails.getCpuInfo(), + "{\"vendor\": \"Intel\", \"model\": \"Westmere\", \"arch\": \"x86_64\", \"features\": [\"pge\", \"avx\", \"clflush\", \"sep\", " + + "\"syscall\", \"vme\", \"tsc\", \"xsave\", \"vmx\", \"cmov\", \"ssse3\", \"pat\", \"lm\", \"msr\", \"nx\", \"fxsr\", \"sse4.1\", " + + "\"pae\", \"sse4.2\", \"pclmuldq\", \"mmx\", \"osxsave\", \"cx8\", \"mce\", \"de\", \"aes\", \"ht\", \"pse\", \"lahf_lm\"," + + " \"popcnt\", \"mca\", \"apic\", \"sse\", \"ds\", \"pni\", \"rdtscp\", \"sse2\", \"ss\", \"hypervisor\", \"pcid\", \"fpu\"," + + " \"cx16\", \"pse36\", \"mtrr\", \"x2apic\"], \"topology\": {\"cores\": 4, \"threads\": 1, \"sockets\": 1}}", + "Unexpected Cpu Info it was: " + hypervisorDetails.getCpuInfo()); + + assertRequests(server, 3, "/os-hypervisors/detail"); + } + + public void testListInDetailWhenResponseIs404(Method method) throws Exception { + MockWebServer server = servers.get(method.getName()); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/extension_list_full.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + NovaApi novaApi = api(server.getUrl("/").toString(), "openstack-nova"); + assertEquals(novaApi.getConfiguredRegions(), ImmutableSet.of("RegionOne", "RegionTwo", "RegionThree")); + + assertTrue(novaApi.getHypervisorApi("RegionOne").get().listInDetail().isEmpty()); + + assertRequests(server, 3, "/os-hypervisors/detail"); + } + + private void assertRequests(MockWebServer server, int requestCount, String requestPath) throws InterruptedException { + assertEquals(server.getRequestCount(), requestCount); + assertAuthentication(server); + assertExtensions(server, "/v2/da0d12be20394afb851716e10a49e4a7"); + if (requestPath != null) { + assertRequest(server.takeRequest(), "GET", "/v2/da0d12be20394afb851716e10a49e4a7" + requestPath); + } + } +} diff --git a/apis/openstack-nova/src/test/resources/access.json b/apis/openstack-nova/src/test/resources/access.json index fab16454bc..219c7c1a19 100644 --- a/apis/openstack-nova/src/test/resources/access.json +++ b/apis/openstack-nova/src/test/resources/access.json @@ -41,6 +41,20 @@ "internalURL": "URL/v2/da0d12be20394afb851716e10a49e4a7", "region": "RegionOne", "adminURL": "URL/v2/da0d12be20394afb851716e10a49e4a7" + }, + { + "publicURL": "URL/v2/ba0d12be20394afb851716e10a49e4a8", + "id": "2122bcaa704343c19ad2578410d4961d", + "internalURL": "URL/v2/ba0d12be20394afb851716e10a49e4a8", + "region": "RegionTwo", + "adminURL": "URL/v2/ba0d12be20394afb851716e10a49e4a8" + }, + { + "publicURL": "URL/v2/ca0d12be20394afb851716e10a49e4a9", + "id": "2122bcaa704343c19ad2578410d4961d", + "internalURL": "URL/v2/ca0d12be20394afb851716e10a49e4a9", + "region": "RegionThree", + "adminURL": "URL/v2/ca0d12be20394afb851716e10a49e4a9" } ] }, diff --git a/apis/openstack-nova/src/test/resources/extension_list_full.json b/apis/openstack-nova/src/test/resources/extension_list_full.json index 2ab0c65368..1d2a1abc20 100644 --- a/apis/openstack-nova/src/test/resources/extension_list_full.json +++ b/apis/openstack-nova/src/test/resources/extension_list_full.json @@ -303,6 +303,14 @@ "namespace": "http://docs.openstack.org/compute/ext/interfaces/api/v1.1", "alias": "os-attach-interfaces", "description": "Attach interface support." + }, + { + "updated": "2012-06-21T00:00:00Z", + "name": "Hypervisors", + "links": [], + "namespace": "http://docs.openstack.org/compute/ext/hypervisors/api/v1.1", + "alias": "os-hypervisors", + "description": "Admin-only hypervisor administration." } ] } diff --git a/apis/openstack-nova/src/test/resources/hypervisor_details.json b/apis/openstack-nova/src/test/resources/hypervisor_details.json new file mode 100644 index 0000000000..3c4adb50ab --- /dev/null +++ b/apis/openstack-nova/src/test/resources/hypervisor_details.json @@ -0,0 +1,40 @@ +{ + "hypervisors": [ + { + "vcpus_used": 5, + "hypervisor_type": "QEMU", + "local_gb_used": 51, + "vcpus": 16, + "hypervisor_hostname": "os-compute1", + "memory_mb_used": 7168, + "memory_mb": 20079, + "current_workload": 0, + "cpu_info": "{\"vendor\": \"Intel\", \"model\": \"Westmere\", \"arch\": \"x86_64\", \"features\": [\"pge\", \"avx\", \"clflush\", \"sep\", \"syscall\", \"vme\", \"tsc\", \"xsave\", \"vmx\", \"cmov\", \"ssse3\", \"pat\", \"lm\", \"msr\", \"nx\", \"fxsr\", \"sse4.1\", \"pae\", \"sse4.2\", \"pclmuldq\", \"mmx\", \"osxsave\", \"cx8\", \"mce\", \"de\", \"aes\", \"ht\", \"pse\", \"lahf_lm\", \"popcnt\", \"mca\", \"apic\", \"sse\", \"ds\", \"pni\", \"rdtscp\", \"sse2\", \"ss\", \"hypervisor\", \"pcid\", \"fpu\", \"cx16\", \"pse36\", \"mtrr\", \"x2apic\"], \"topology\": {\"cores\": 4, \"threads\": 1, \"sockets\": 1}}", + "running_vms": 2, + "free_disk_gb": 144, + "hypervisor_version": 2000000, + "disk_available_least": 131, + "local_gb": 195, + "free_ram_mb": 12911, + "id": 1 + }, + { + "vcpus_used": 8, + "hypervisor_type": "QEMU", + "local_gb_used": 130, + "vcpus": 16, + "hypervisor_hostname": "os-compute02", + "memory_mb_used": 14848, + "memory_mb": 20079, + "current_workload": 0, + "cpu_info": "{\"vendor\": \"Intel\", \"model\": \"Westmere\", \"arch\": \"x86_64\", \"features\": [\"pge\", \"avx\", \"clflush\", \"sep\", \"syscall\", \"vme\", \"tsc\", \"xsave\", \"vmx\", \"cmov\", \"ssse3\", \"pat\", \"lm\", \"msr\", \"nx\", \"fxsr\", \"sse4.1\", \"pae\", \"sse4.2\", \"pclmuldq\", \"mmx\", \"osxsave\", \"cx8\", \"mce\", \"de\", \"aes\", \"ht\", \"pse\", \"lahf_lm\", \"popcnt\", \"mca\", \"apic\", \"sse\", \"ds\", \"pni\", \"rdtscp\", \"sse2\", \"ss\", \"hypervisor\", \"pcid\", \"fpu\", \"cx16\", \"pse36\", \"mtrr\", \"x2apic\"], \"topology\": {\"cores\": 4, \"threads\": 1, \"sockets\": 1}}", + "running_vms": 3, + "free_disk_gb": 65, + "hypervisor_version": 2000000, + "disk_available_least": 38, + "local_gb": 195, + "free_ram_mb": 5231, + "id": 4 + } + ] +} diff --git a/apis/openstack-nova/src/test/resources/hypervisor_list.json b/apis/openstack-nova/src/test/resources/hypervisor_list.json new file mode 100644 index 0000000000..375d152384 --- /dev/null +++ b/apis/openstack-nova/src/test/resources/hypervisor_list.json @@ -0,0 +1,12 @@ +{ + "hypervisors": [ + { + "id": 1, + "hypervisor_hostname": "os-compute1" + }, + { + "id": 4, + "hypervisor_hostname": "os-compute02" + } + ] +}