Adding missing "hosts" field to OpenStack Nova AvailabilityZone

This commit is contained in:
Arvind Nadendla 2015-07-10 02:32:21 -07:00 committed by Zack Shoylev
parent 3445f00a88
commit 5d21b3e056
10 changed files with 389 additions and 26 deletions

View File

@ -0,0 +1,116 @@
/*
* 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.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.SerializedName;
import java.beans.ConstructorProperties;
import java.util.Date;
import java.util.Map;
public class AvailabilityZone {
public static final class HostService {
private final boolean available;
private final boolean active;
@SerializedName("updated_at")
private final Date updated;
@ConstructorProperties({"available", "active", "updated_at"})
protected HostService(boolean available, boolean active, Date updated) {
this.available = available;
this.active = active;
this.updated = updated;
}
public boolean isAvailable() { return available; }
public boolean isActive() { return active; }
public Date getUpdated() { return updated; }
protected Objects.ToStringHelper string() {
return Objects.toStringHelper(this)
.add("available", available)
.add("active", active)
.add("updated", updated);
}
@Override
public String toString() {
return string().toString();
}
}
@SerializedName("zoneName")
private final String name;
private final ZoneState state;
private final Map<String, Map<String, HostService>> hosts;
@ConstructorProperties({"zoneName" , "zoneState", "hosts"})
protected AvailabilityZone(String name, ZoneState state, Map<String, Map<String, HostService>> hosts) {
this.name = name;
this.state = state;
this.hosts = hosts == null ? ImmutableMap.<String, Map<String, HostService>>of() : ImmutableMap.copyOf(hosts);
}
public String getName() {
return name;
}
public ZoneState getState() {
return state;
}
/**
* @return returns a map of host name and Host service objects
*/
public Map<String, Map<String, HostService>> getHosts() {
return this.hosts;
}
@Override
public int hashCode() {
return Objects.hashCode(name, state, hosts);
}
@Override
public boolean equals(Object obj) {
if (this != obj)
return false;
if (obj == null || getClass() != obj.getClass()) return false;
AvailabilityZone that = AvailabilityZone.class.cast(obj);
return Objects.equal(this.name, that.name) && Objects.equal(this.state, that.state) && Objects.equal(this.hosts,
that.hosts);
}
protected Objects.ToStringHelper string() {
return Objects.toStringHelper(this)
.add("name", name)
.add("state", state)
.add("Hosts", hosts);
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.common.base.Objects;
public class ZoneState {
private final boolean available;
protected ZoneState(boolean available) { this.available = available; }
public boolean isAvailable() { return this.available; }
@Override
public int hashCode() {
return Objects.hashCode(available);
}
@Override
public boolean equals(Object obj) {
if (this != obj) return false;
if (obj == null || getClass() != obj.getClass()) return false;
ZoneState that = ZoneState.class.cast(obj);
return Objects.equal(this.available, that.available);
}
protected Objects.ToStringHelper string() {
return Objects.toStringHelper(this)
.add("available", available);
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -16,11 +16,16 @@
*/
package org.jclouds.openstack.nova.v2_0.domain.zonescoped;
import java.beans.ConstructorProperties;
import com.google.common.base.Objects;
import com.google.gson.annotations.SerializedName;
import java.beans.ConstructorProperties;
/**
* @deprecated This package has been replaced with {@link org.jclouds.openstack.nova.v2_0.domain.regionscoped}.
* Please use {@link org.jclouds.openstack.nova.v2_0.domain.regionscoped.AvailabilityZone AvailabilityZone}
* instead. To be removed in jclouds 2.0.
*/
public class AvailabilityZone {
@SerializedName("zoneName")

View File

@ -18,6 +18,11 @@ package org.jclouds.openstack.nova.v2_0.domain.zonescoped;
import com.google.common.base.Objects;
/**
* @deprecated This package has been replaced with {@link org.jclouds.openstack.nova.v2_0.domain.regionscoped}.
* Please use {@link org.jclouds.openstack.nova.v2_0.domain.regionscoped.ZoneState ZoneState}
* instead. To be removed in jclouds 2.0.
*/
public class ZoneState {
private final boolean available;

View File

@ -16,23 +16,22 @@
*/
package org.jclouds.openstack.nova.v2_0.extensions;
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;
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.zonescoped.AvailabilityZone;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.AvailabilityZone;
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 com.google.common.annotations.Beta;
import com.google.common.collect.FluentIterable;
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) Availability Zone Extension API.
@ -43,6 +42,18 @@ import com.google.common.collect.FluentIterable;
@Consumes(MediaType.APPLICATION_JSON)
@Path("/os-availability-zone")
public interface AvailabilityZoneApi {
/**
* @return all availability zones
* @deprecated Please use {@link #listAvailabilityZones()} instead. To be removed in jclouds 2.0.
*/
@Deprecated
@Named("availabilityZone:list")
@GET
@SelectJson("availabilityZoneInfo")
@Fallback(EmptyFluentIterableOnNotFoundOr404.class)
FluentIterable<org.jclouds.openstack.nova.v2_0.domain.zonescoped.AvailabilityZone> list();
/**
* @return all availability zones
*/
@ -50,5 +61,5 @@ public interface AvailabilityZoneApi {
@GET
@SelectJson("availabilityZoneInfo")
@Fallback(EmptyFluentIterableOnNotFoundOr404.class)
FluentIterable<AvailabilityZone> list();
FluentIterable<AvailabilityZone> listAvailabilityZones();
}

View File

@ -19,14 +19,15 @@ 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 org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.AvailabilityZone;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.AvailabilityZone;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
import org.testng.annotations.Test;
import java.util.Date;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@ -49,12 +50,27 @@ public class AvailabilityZoneApiExpectTest extends BaseNovaApiExpectTest {
assertEquals(availabilityZonesApi.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1", "az-2.region-a.geo-1", "az-3.region-a.geo-1"));
FluentIterable<? extends AvailabilityZone> zones = availabilityZonesApi.getAvailabilityZoneApi("az-1.region-a.geo-1").get().list();
FluentIterable<? extends AvailabilityZone> zones = availabilityZonesApi.getAvailabilityZoneApi("az-1.region-a.geo-1").get().listAvailabilityZones();
Optional<? extends AvailabilityZone> zone = zones.first();
assertTrue(zone.isPresent(), "Couldn't find zone");
assertEquals(zone.get().getName(), "nova", "Expected zone name to be nova but it was: " + zone.get().getName());
assertTrue(zone.get().getState().available(), "Zone: " + zone.get().getName() + " is not available.");
assertEquals(zone.get()
.getName(), "internal", "Expected zone name to be internal but it was: " + zone.get()
.getName());
assertTrue(zone.get()
.getState()
.isAvailable(), "Zone: " + zone.get()
.getName() + " is not available.");
String hostName = zone.get().getHosts().keySet().iterator().next();
assertEquals(hostName, "os-controller", "Expected host name to be os-controller but it was: " + hostName);
String hostServiceName = zone.get().getHosts().get(hostName).keySet().iterator().next();
assertEquals(hostServiceName, "nova-conductor",
"Expected host service name to be nova-conductor but it was: " + hostServiceName);
AvailabilityZone.HostService hostService = zone.get().getHosts().get(hostName).get(hostServiceName);
assertTrue(hostService.isAvailable(), "Couldn't find host service availability");
assertTrue(hostService.isActive(), "Couldn't find host service state");
assertEquals(hostService.getUpdated(), new Date(1436509815000L),
"Expected Updated time: " + new Date(1436509815000L) + " does match Updated time : " + hostService.getUpdated());
}
}

View File

@ -16,15 +16,14 @@
*/
package org.jclouds.openstack.nova.v2_0.extensions;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.AvailabilityZone;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import org.jclouds.openstack.nova.v2_0.domain.regionscoped.AvailabilityZone;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
@Test(groups = "live", testName = "AvailabilityZonesApiLiveTest")
public class AvailabilityZonesApiLiveTest extends BaseNovaApiLiveTest {
@ -34,11 +33,21 @@ public class AvailabilityZonesApiLiveTest extends BaseNovaApiLiveTest {
Optional<? extends AvailabilityZoneApi> availabilityZoneApi = api.getAvailabilityZoneApi("RegionOne");
if (availabilityZoneApi.isPresent()) {
FluentIterable<? extends AvailabilityZone> zones = availabilityZoneApi.get().list();
FluentIterable<? extends AvailabilityZone> zones = availabilityZoneApi.get().listAvailabilityZones();
for (AvailabilityZone zone : zones) {
assertNotNull(zone.getName());
assertTrue(zone.getState().available(), "zone: " + zone.getName() + " is not available.");
assertTrue(zone.getState()
.isAvailable(), "zone: " + zone.getName() + " is not available.");
String hostName = zone.getHosts().keySet().iterator().next();
assertNotNull(hostName, "Expected host name to be not null");
String hostServiceName = zone.getHosts().get(hostName).keySet().iterator().next();
assertNotNull(hostServiceName, "Expected host service name to be not null");
AvailabilityZone.HostService hostService = zone.getHosts().get(hostName).get(hostServiceName);
assertTrue(hostService.isAvailable(), "Couldn't find host service availability");
assertTrue(hostService.isActive(), "Couldn't find host service state");
assertNotNull(hostService.getUpdated(), "Expected Updated time, but none received ");
}
}
}

View File

@ -0,0 +1,60 @@
/*
* 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 org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.domain.zonescoped.AvailabilityZone;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@Test(groups = "unit", testName = "DeprecatedAvailabilityZoneApiExpectTest")
public class DeprecatedAvailabilityZoneApiExpectTest extends BaseNovaApiExpectTest {
public void testAvailabilityZonesList() throws Exception {
HttpRequest list = HttpRequest
.builder()
.method("GET")
.endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456/os-availability-zone")
.addHeader("Accept", "application/json")
.addHeader("X-Auth-Token", authToken).build();
HttpResponse listResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/listAvailabilityZones.json")).build();
NovaApi availabilityZonesApi = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list, listResponse);
assertEquals(availabilityZonesApi.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1", "az-2.region-a.geo-1", "az-3.region-a.geo-1"));
FluentIterable<? extends AvailabilityZone> zones = availabilityZonesApi.getAvailabilityZoneApi("az-1.region-a.geo-1").get().list();
Optional<? extends AvailabilityZone> zone = zones.first();
assertTrue(zone.isPresent(), "Couldn't find zone");
assertEquals(zone.get().getName(), "internal",
"Expected zone name to be internal but it was: " + zone.get().getName());
assertTrue(zone.get().getState().available(), "Zone: " + zone.get().getName() + " is not available.");
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.zonescoped.AvailabilityZone;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
import org.testng.annotations.Test;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
@Test(groups = "live", testName = "DeprecatedAvailabilityZonesApiLiveTest")
public class DeprecatedAvailabilityZonesApiLiveTest extends BaseNovaApiLiveTest {
@Test
public void testListAvailabilityZones() throws Exception {
Optional<? extends AvailabilityZoneApi> availabilityZoneApi = api.getAvailabilityZoneApi("RegionOne");
if (availabilityZoneApi.isPresent()) {
FluentIterable<? extends AvailabilityZone> zones = availabilityZoneApi.get().list();
for (AvailabilityZone zone : zones) {
assertNotNull(zone.getName());
assertTrue(zone.getState().available(), "zone: " + zone.getName() + " is not available.");
}
}
}
}

View File

@ -4,7 +4,52 @@
"zoneState": {
"available": true
},
"hosts": null,
"hosts": {
"os-controller": {
"nova-conductor": {
"available": true,
"active": true,
"updated_at": "2015-07-10T06:30:15.000000"
},
"nova-consoleauth": {
"available": true,
"active": true,
"updated_at": "2015-07-10T06:30:20.000000"
},
"nova-cert": {
"available": true,
"active": true,
"updated_at": "2015-07-10T06:30:19.000000"
},
"nova-scheduler": {
"available": true,
"active": true,
"updated_at": "2015-07-10T06:30:12.000000"
}
}
},
"zoneName": "internal"
},
{
"zoneState": {
"available": true
},
"hosts": {
"os-compute02": {
"nova-compute": {
"available": true,
"active": true,
"updated_at": "2015-07-10T06:30:16.000000"
}
},
"os-compute01": {
"nova-compute": {
"available": true,
"active": true,
"updated_at": "2015-07-10T06:30:12.000000"
}
}
},
"zoneName": "nova"
}
]