Some useful predicates for Load Balancers.

This commit is contained in:
Everett Toews 2012-12-20 15:11:04 -06:00
parent 532298ebb0
commit a48ec87ff8
6 changed files with 179 additions and 192 deletions

View File

@ -1,68 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.rackspace.cloudloadbalancers.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApi;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
* Tests to see if a loadBalancer is running
*
* @author Adrian Cole
*/
@Singleton
public class LoadBalancerActive implements Predicate<LoadBalancer> {
private final CloudLoadBalancersApi client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public LoadBalancerActive(CloudLoadBalancersApi client) {
this.client = client;
}
public boolean apply(LoadBalancer loadBalancer) {
logger.trace("looking for status on loadBalancer %s", checkNotNull(loadBalancer, "loadBalancer"));
loadBalancer = refresh(loadBalancer);
if (loadBalancer == null)
return false;
logger.trace("%s: looking for loadBalancer status %s: currently: %s", loadBalancer.getId(), Status.ACTIVE,
loadBalancer.getStatus());
if (loadBalancer.getStatus() == Status.ERROR)
throw new IllegalStateException("loadBalancer in error status: " + loadBalancer);
return loadBalancer.getStatus() == Status.ACTIVE;
}
private LoadBalancer refresh(LoadBalancer loadBalancer) {
return client.getLoadBalancerApiForZone(loadBalancer.getRegion()).get(loadBalancer.getId());
}
}

View File

@ -1,66 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.rackspace.cloudloadbalancers.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApi;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer.Status;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
* Tests to see if a loadBalancer is deleted
*
* @author Adrian Cole
*/
@Singleton
public class LoadBalancerDeleted implements Predicate<LoadBalancer> {
private final CloudLoadBalancersApi client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public LoadBalancerDeleted(CloudLoadBalancersApi client) {
this.client = client;
}
public boolean apply(LoadBalancer loadBalancer) {
logger.trace("looking for status on loadBalancer %s", checkNotNull(loadBalancer, "loadBalancer"));
loadBalancer = refresh(loadBalancer);
if (loadBalancer == null)
return true;
logger.trace("%s: looking for loadBalancer status %s: currently: %s", loadBalancer.getId(), Status.DELETED,
loadBalancer.getStatus());
return loadBalancer.getStatus() == Status.DELETED;
}
private LoadBalancer refresh(LoadBalancer loadBalancer) {
return client.getLoadBalancerApiForZone(loadBalancer.getRegion()).get(loadBalancer.getId());
}
}

View File

@ -0,0 +1,142 @@
/**
* 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.rackspace.cloudloadbalancers.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.concurrent.TimeUnit;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.features.LoadBalancerApi;
import com.google.common.base.Predicate;
/**
* Tests to see if loadBalancer has reached status. This class is most useful when paired with a RetryablePredicate as
* in the code below. This class can be used to block execution until the LoadBalancer status has reached a desired state.
* This is useful when your LoadBalancer needs to be 100% ready before you can continue with execution.
* <br/>
* <pre>
* {@code
* LoadBalancer loadBalancer = loadBalancerApi.create(loadBalancerRequest);
*
* RetryablePredicate<String> awaitAvailable = new RetryablePredicate<String>(
* LoadBalancerPredicates.available(loadBalancerApi), 600, 10, 10, TimeUnit.SECONDS);
*
* if (!awaitAvailable.apply(loadBalancer)) {
* throw new TimeoutException("Timeout on loadBalancer: " + loadBalancer);
* }
* }
* </pre>
*
* You can also use the static convenience methods as so.
* <br/>
* <pre>
* {@code
* LoadBalancer loadBalancer = loadBalancerApi.create(loadBalancerRequest);
*
* if (!LoadBalancerPredicates.awaitAvailable(loadBalancerApi).apply(loadBalancer)) {
* throw new TimeoutException("Timeout on loadBalancer: " + loadBalancer);
* }
* }
* </pre>
*
* @author Everett Toews
*/
public class LoadBalancerPredicates {
/**
* Wait until a LoadBalancer is Available.
*
* @param loadBalancerApi The LoadBalancerApi in the zone where your LoadBalancer resides.
* @return RetryablePredicate That will check the status every 3 seconds for a maxiumum of 5 minutes.
*/
public static RetryablePredicate<LoadBalancer> awaitAvailable(LoadBalancerApi loadBalancerApi) {
StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(loadBalancerApi, LoadBalancer.Status.ACTIVE);
return new RetryablePredicate<LoadBalancer>(statusPredicate, 300, 3, 3, TimeUnit.SECONDS);
}
/**
* Wait until a LoadBalancer no longer exists.
*
* @param loadBalancerApi The LoadBalancerApi in the zone where your LoadBalancer resides.
* @return RetryablePredicate That will check the whether the LoadBalancer exists
* every 3 seconds for a maxiumum of 5 minutes.
*/
public static RetryablePredicate<LoadBalancer> awaitDeleted(LoadBalancerApi loadBalancerApi) {
DeletedPredicate deletedPredicate = new DeletedPredicate(loadBalancerApi);
return new RetryablePredicate<LoadBalancer>(deletedPredicate, 300, 3, 3, TimeUnit.SECONDS);
}
public static RetryablePredicate<LoadBalancer> awaitStatus(
LoadBalancerApi loadBalancerApi, LoadBalancer.Status status, long maxWaitInSec, long periodInSec) {
StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(loadBalancerApi, status);
return new RetryablePredicate<LoadBalancer>(statusPredicate, maxWaitInSec, periodInSec, periodInSec, TimeUnit.SECONDS);
}
private static class StatusUpdatedPredicate implements Predicate<LoadBalancer> {
private LoadBalancerApi loadBalancerApi;
private LoadBalancer.Status status;
public StatusUpdatedPredicate(LoadBalancerApi loadBalancerApi, LoadBalancer.Status status) {
this.loadBalancerApi = checkNotNull(loadBalancerApi, "loadBalancerApi must be defined");
this.status = checkNotNull(status, "status must be defined");
}
/**
* @return boolean Return true when the loadBalancer reaches status, false otherwise
*/
@Override
public boolean apply(LoadBalancer loadBalancer) {
checkNotNull(loadBalancer, "loadBalancer must be defined");
LoadBalancer loadBalancerUpdated = loadBalancerApi.get(loadBalancer.getId());
checkNotNull(loadBalancerUpdated, "LoadBalancer %s not found.", loadBalancer.getId());
return status.equals(loadBalancerUpdated.getStatus());
}
}
private static class DeletedPredicate implements Predicate<LoadBalancer> {
private LoadBalancerApi loadBalancerApi;
public DeletedPredicate(LoadBalancerApi loadBalancerApi) {
this.loadBalancerApi = checkNotNull(loadBalancerApi, "loadBalancerApi must be defined");
}
/**
* @return boolean Return true when the snapshot is deleted, false otherwise
*/
@Override
public boolean apply(LoadBalancer loadBalancer) {
checkNotNull(loadBalancer, "loadBalancer must be defined");
LoadBalancer loadBalancerUpdate = loadBalancerApi.get(loadBalancer.getId());
if (loadBalancerUpdate == null) {
return true;
}
else {
return loadBalancerUpdate.getStatus().equals(LoadBalancer.Status.DELETED);
}
}
}
}

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.rackspace.cloudloadbalancers.features;
import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitAvailable;
import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitDeleted;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
@ -48,18 +50,18 @@ public class LoadBalancerApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
@AfterGroups(groups = "live")
protected void tearDownContext() {
for (LoadBalancer lb: lbs) {
assert loadBalancerActive.apply(lb) : lb;
client.getLoadBalancerApiForZone(lb.getRegion()).remove(lb.getId());
assert loadBalancerDeleted.apply(lb) : lb;
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
clbApi.getLoadBalancerApiForZone(lb.getRegion()).remove(lb.getId());
assertTrue(awaitDeleted(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
}
super.tearDownContext();
}
public void testCreateLoadBalancer() throws Exception {
for (String zone: client.getConfiguredZones()) {
for (String zone: clbApi.getConfiguredZones()) {
Logger.getAnonymousLogger().info("starting lb in region " + zone);
LoadBalancer lb = client.getLoadBalancerApiForZone(zone).create(
LoadBalancer lb = clbApi.getLoadBalancerApiForZone(zone).create(
LoadBalancerRequest.builder()
.name(prefix + "-" + zone)
.protocol("HTTP")
@ -76,9 +78,9 @@ public class LoadBalancerApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
lbs.add(lb);
assertTrue(loadBalancerActive.apply(lb));
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
LoadBalancer newLb = client.getLoadBalancerApiForZone(zone).get(lb.getId());
LoadBalancer newLb = clbApi.getLoadBalancerApiForZone(zone).get(lb.getId());
checkLBInRegion(zone, newLb, prefix + "-" + zone);
assertEquals(newLb.getStatus(), LoadBalancer.Status.ACTIVE);
@ -88,12 +90,12 @@ public class LoadBalancerApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
@Test(dependsOnMethods = "testCreateLoadBalancer")
public void testUpdateLoadBalancer() throws Exception {
for (LoadBalancer lb: lbs) {
client.getLoadBalancerApiForZone(lb.getRegion()).update(lb.getId(),
clbApi.getLoadBalancerApiForZone(lb.getRegion()).update(lb.getId(),
LoadBalancerAttributes.Builder.name("foo" + "-" + lb.getRegion()));
assertTrue(loadBalancerActive.apply(lb));
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
LoadBalancer newLb = client.getLoadBalancerApiForZone(lb.getRegion()).get(lb.getId());
LoadBalancer newLb = clbApi.getLoadBalancerApiForZone(lb.getRegion()).get(lb.getId());
checkLBInRegion(newLb.getRegion(), newLb, "foo" + "-" + lb.getRegion());
assertEquals(newLb.getStatus(), LoadBalancer.Status.ACTIVE);
@ -102,9 +104,9 @@ public class LoadBalancerApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
@Test(dependsOnMethods = "testUpdateLoadBalancer")
public void testListLoadBalancers() throws Exception {
for (String zone: client.getConfiguredZones()) {
for (String zone: clbApi.getConfiguredZones()) {
Set<LoadBalancer> response = client.getLoadBalancerApiForZone(zone).list().concat().toImmutableSet();
Set<LoadBalancer> response = clbApi.getLoadBalancerApiForZone(zone).list().concat().toImmutableSet();
assertNotNull(response);
assertTrue(response.size() >= 0);
@ -124,7 +126,7 @@ public class LoadBalancerApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
// node info not available during list;
assert lb.getNodes().size() == 0 : lb;
LoadBalancer getDetails = client.getLoadBalancerApiForZone(zone).get(lb.getId());
LoadBalancer getDetails = clbApi.getLoadBalancerApiForZone(zone).get(lb.getId());
try {
assertEquals(getDetails.getRegion(), lb.getRegion());

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.rackspace.cloudloadbalancers.features;
import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitAvailable;
import static org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerPredicates.awaitDeleted;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@ -51,16 +53,16 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
private Map<LoadBalancer, Set<Node>> nodes = Maps.newHashMap();
public void testCreateLoadBalancers() {
assertTrue(client.getConfiguredZones().size() > 0, "Need to have some zones!");
Logger.getAnonymousLogger().info("running against zones " + client.getConfiguredZones());
for (String zone : client.getConfiguredZones()) {
assertTrue(clbApi.getConfiguredZones().size() > 0, "Need to have some zones!");
Logger.getAnonymousLogger().info("running against zones " + clbApi.getConfiguredZones());
for (String zone : clbApi.getConfiguredZones()) {
Logger.getAnonymousLogger().info("starting lb in zone " + zone);
LoadBalancer lb = client.getLoadBalancerApiForZone(zone).create(
LoadBalancer lb = clbApi.getLoadBalancerApiForZone(zone).create(
LoadBalancerRequest.builder().name(prefix + "-" + zone).protocol("HTTP").port(80).virtualIPType(
Type.PUBLIC).node(NodeRequest.builder().address("192.168.1.1").port(8080).build()).build());
nodes.put(lb, new HashSet<Node>());
assert loadBalancerActive.apply(lb) : lb;
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
}
}
@ -69,17 +71,17 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
for (LoadBalancer lb : nodes.keySet()) {
String region = lb.getRegion();
Logger.getAnonymousLogger().info("starting node on loadbalancer " + lb.getId() + " in region " + region);
Set<Node> newNodes = client.getNodeApiForZoneAndLoadBalancer(region, lb.getId()).add(
Set<Node> newNodes = clbApi.getNodeApiForZoneAndLoadBalancer(region, lb.getId()).add(
ImmutableSet.<NodeRequest> of(NodeRequest.builder().address("192.168.1.2").port(8080).build()));
for (Node n : newNodes) {
assertEquals(n.getStatus(), Node.Status.ONLINE);
nodes.get(lb).add(n);
assertEquals(client.getNodeApiForZoneAndLoadBalancer(region, lb.getId()).get(n.getId()).getStatus(),
assertEquals(clbApi.getNodeApiForZoneAndLoadBalancer(region, lb.getId()).get(n.getId()).getStatus(),
Node.Status.ONLINE);
}
assert loadBalancerActive.apply(lb) : lb;
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
}
}
@ -88,12 +90,12 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
for (Entry<LoadBalancer, Set<Node>> entry : nodes.entrySet()) {
for (Node n : entry.getValue()) {
String region = entry.getKey().getRegion();
client.getNodeApiForZoneAndLoadBalancer(region, entry.getKey().getId()).update(n.getId(),
clbApi.getNodeApiForZoneAndLoadBalancer(region, entry.getKey().getId()).update(n.getId(),
NodeAttributes.Builder.weight(23));
assertEquals(client.getNodeApiForZoneAndLoadBalancer(region, entry.getKey().getId()).get(n.getId())
assertEquals(clbApi.getNodeApiForZoneAndLoadBalancer(region, entry.getKey().getId()).get(n.getId())
.getStatus(), Node.Status.ONLINE);
Node newNode = client.getNodeApiForZoneAndLoadBalancer(region, entry.getKey().getId()).get(n.getId());
Node newNode = clbApi.getNodeApiForZoneAndLoadBalancer(region, entry.getKey().getId()).get(n.getId());
assertEquals(newNode.getStatus(), Node.Status.ONLINE);
assertEquals(newNode.getWeight(), (Integer) 23);
}
@ -103,7 +105,7 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
@Test(dependsOnMethods = "testModifyNode")
public void testListNodes() throws Exception {
for (LoadBalancer lb : nodes.keySet()) {
Set<Node> response = client.getNodeApiForZoneAndLoadBalancer(lb.getRegion(), lb.getId()).list().concat().toImmutableSet();
Set<Node> response = clbApi.getNodeApiForZoneAndLoadBalancer(lb.getRegion(), lb.getId()).list().concat().toImmutableSet();
assert null != response;
assertTrue(response.size() >= 0);
for (Node n : response) {
@ -115,7 +117,7 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
assert !Arrays.asList(LoadBalancer.WEIGHTED_ALGORITHMS).contains(lb.getTypedAlgorithm())
|| n.getWeight() != null : n;
Node getDetails = client.getNodeApiForZoneAndLoadBalancer(lb.getRegion(), lb.getId()).get(n.getId());
Node getDetails = clbApi.getNodeApiForZoneAndLoadBalancer(lb.getRegion(), lb.getId()).get(n.getId());
try {
assertEquals(getDetails.getId(), n.getId());
@ -138,13 +140,13 @@ public class NodeApiLiveTest extends BaseCloudLoadBalancersApiLiveTest {
protected void tearDownContext() {
for (Entry<LoadBalancer, Set<Node>> entry : nodes.entrySet()) {
LoadBalancer lb = entry.getKey();
LoadBalancerApi lbClient = client.getLoadBalancerApiForZone(lb.getRegion());
LoadBalancerApi lbClient = clbApi.getLoadBalancerApiForZone(lb.getRegion());
if (lbClient.get(lb.getId()).getStatus() != Status.DELETED) {
assert loadBalancerActive.apply(lb) : lb;
assertTrue(awaitAvailable(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
lbClient.remove(lb.getId());
}
assert loadBalancerDeleted.apply(lb) : lb;
assertTrue(awaitDeleted(clbApi.getLoadBalancerApiForZone(lb.getRegion())).apply(lb));
}
super.tearDownContext();
}

View File

@ -19,62 +19,37 @@
package org.jclouds.rackspace.cloudloadbalancers.internal;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.jclouds.apis.BaseContextLiveTest;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApi;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApiMetadata;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersAsyncApi;
import org.jclouds.rackspace.cloudloadbalancers.CloudLoadBalancersApi;
import org.jclouds.rackspace.cloudloadbalancers.domain.LoadBalancer;
import org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerActive;
import org.jclouds.rackspace.cloudloadbalancers.predicates.LoadBalancerDeleted;
import org.jclouds.rest.RestContext;
import org.testng.annotations.BeforeGroups;
import com.google.common.base.Predicate;
import com.google.common.net.HostAndPort;
import com.google.common.reflect.TypeToken;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
*
* @author Adrian Cole
*/
public class BaseCloudLoadBalancersApiLiveTest extends BaseContextLiveTest<RestContext<CloudLoadBalancersApi, CloudLoadBalancersAsyncApi>> {
protected CloudLoadBalancersApi clbApi;
public BaseCloudLoadBalancersApiLiveTest() {
provider = "rackspace-cloudloadbalancers";
}
protected CloudLoadBalancersApi client;
protected Predicate<HostAndPort> socketTester;
protected RetryablePredicate<LoadBalancer> loadBalancerActive;
protected RetryablePredicate<LoadBalancer> loadBalancerDeleted;
protected Injector injector;
@BeforeGroups(groups = { "integration", "live" })
@Override
public void setupContext() {
super.setupContext();
client = context.getApi();
injector = Guice.createInjector(new SLF4JLoggingModule());
clbApi = context.getApi();
loadBalancerActive = new RetryablePredicate<LoadBalancer>(
new LoadBalancerActive(client), 300, 1, 1, TimeUnit.SECONDS);
injector.injectMembers(loadBalancerActive);
loadBalancerDeleted = new RetryablePredicate<LoadBalancer>(
new LoadBalancerDeleted(client), 300, 1, 1, TimeUnit.SECONDS);
injector.injectMembers(loadBalancerDeleted);
Logger.getAnonymousLogger().info("running against zones " + client.getConfiguredZones());
Logger.getAnonymousLogger().info("running against zones " + clbApi.getConfiguredZones());
}
@Override