Skip to content
Permalink
Browse files
Refactor DimensionDataCloudControlResponseUtils waitFor* methods so t…
…hat they are injectable.
  • Loading branch information
trevorflanagan authored and nacx committed Dec 18, 2017
1 parent eaeea5c commit 889b34b96eac8db612a72065c0db672f4bee5add
Showing 15 changed files with 397 additions and 400 deletions.
@@ -20,12 +20,15 @@
import com.google.inject.Module;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlComputeServiceContextModule;
import org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlHttpApiModule;
import org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlParserModule;
import org.jclouds.rest.internal.BaseHttpApiMetadata;

import java.net.URI;
import java.util.Properties;

import static org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataProperties.OPERATION_TIMEOUT;
import static org.jclouds.reflect.Reflection2.typeToken;

public class DimensionDataCloudControlApiMetadata extends BaseHttpApiMetadata<DimensionDataCloudControlApi> {
@@ -46,14 +49,16 @@ protected DimensionDataCloudControlApiMetadata(Builder builder) {
public static class Builder extends BaseHttpApiMetadata.Builder<DimensionDataCloudControlApi, Builder> {

protected Builder() {
final Properties defaultProperties = DimensionDataCloudControlApiMetadata.defaultProperties();
defaultProperties.put(OPERATION_TIMEOUT, 30 * 60 * 1000);
id("dimensiondata-cloudcontrol").name("DimensionData CloudControl API").identityName("user name")
.credentialName("user password")
.documentation(URI.create("http://www.dimensiondata.com/en-US/Solutions/Cloud"))
.defaultEndpoint("https://api-REGION.dimensiondata.com/caas").version("2.4")
.defaultProperties(DimensionDataCloudControlApiMetadata.defaultProperties())
.view(typeToken(ComputeServiceContext.class)).defaultModules(
.defaultProperties(defaultProperties).view(typeToken(ComputeServiceContext.class)).defaultModules(
ImmutableSet.<Class<? extends Module>>builder().add(DimensionDataCloudControlHttpApiModule.class)
.add(DimensionDataCloudControlParserModule.class).build());
.add(DimensionDataCloudControlParserModule.class)
.add(DimensionDataCloudControlComputeServiceContextModule.class).build());
}

@Override
@@ -26,10 +26,8 @@
import org.jclouds.dimensiondata.cloudcontrol.domain.NatRule;
import org.jclouds.dimensiondata.cloudcontrol.domain.PublicIpBlock;
import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
import org.jclouds.dimensiondata.cloudcontrol.domain.State;
import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
import org.jclouds.dimensiondata.cloudcontrol.features.ServerApi;
import org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils;
import org.jclouds.logging.Logger;

import javax.annotation.Resource;
@@ -39,8 +37,9 @@
import java.util.List;

import static java.lang.String.format;
import static org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlComputeServiceContextModule.SERVER_DELETED_PREDICATE;
import static org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlComputeServiceContextModule.SERVER_STOPPED_PREDICATE;
import static org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.generateFirewallRuleName;
import static org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForServerState;

@Singleton
public class CleanupServer implements Function<String, Boolean> {
@@ -51,11 +50,17 @@ public class CleanupServer implements Function<String, Boolean> {

private final DimensionDataCloudControlApi api;
private final Timeouts timeouts;
private Predicate<String> serverStoppedPredicate;
private Predicate<String> serverDeletedPredicate;

@Inject
CleanupServer(final DimensionDataCloudControlApi api, final Timeouts timeouts) {
CleanupServer(final DimensionDataCloudControlApi api, final Timeouts timeouts,
@Named(SERVER_STOPPED_PREDICATE) final Predicate<String> serverStoppedPredicate,
@Named(SERVER_DELETED_PREDICATE) final Predicate<String> serverDeletedPredicate) {
this.api = api;
this.timeouts = timeouts;
this.serverStoppedPredicate = serverStoppedPredicate;
this.serverDeletedPredicate = serverDeletedPredicate;
}

@Override
@@ -118,11 +123,15 @@ public boolean apply(FirewallRule firewallRule) {

serverApi.powerOffServer(serverId);
String message = format("Server(%s) not terminated within %d ms.", serverId, timeouts.nodeTerminated);
DimensionDataCloudControlResponseUtils
.waitForServerStatus(serverApi, serverId, false, true, timeouts.nodeTerminated, message);
if (!serverStoppedPredicate.apply(serverId)) {
throw new IllegalStateException(message);
}
serverApi.deleteServer(serverId);
String deleteFailureMessage = format("Server(%s) not deleted within %d ms.", serverId, timeouts.nodeTerminated);
waitForServerState(serverApi, serverId, State.DELETED, timeouts.nodeTerminated, deleteFailureMessage);

if (!serverDeletedPredicate.apply(serverId)) {
throw new IllegalStateException(deleteFailureMessage);
}
return true;
}

@@ -0,0 +1,252 @@
/*
* 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.dimensiondata.cloudcontrol.config;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi;
import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
import org.jclouds.dimensiondata.cloudcontrol.domain.Server;
import org.jclouds.dimensiondata.cloudcontrol.domain.State;
import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
import org.jclouds.dimensiondata.cloudcontrol.domain.VmTools;
import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
import org.jclouds.dimensiondata.cloudcontrol.features.ServerApi;
import org.jclouds.logging.Logger;

import javax.annotation.Resource;
import javax.inject.Named;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataProperties.OPERATION_TIMEOUT;
import static org.jclouds.util.Predicates2.retry;

public class DimensionDataCloudControlComputeServiceContextModule extends AbstractModule {

@Resource
private Logger logger = Logger.NULL;

public static final String VLAN_DELETED_PREDICATE = "VLAN_DELETED_PREDICATE";
public static final String VLAN_NORMAL_PREDICATE = "VLAN_NORMAL_PREDICATE";
public static final String NETWORK_DOMAIN_DELETED_PREDICATE = "NETWORK_DOMAIN_DELETED_PREDICATE";
public static final String NETWORK_DOMAIN_NORMAL_PREDICATE = "NETWORK_DOMAIN_NORMAL_PREDICATE";
public static final String SERVER_STARTED_PREDICATE = "SERVER_STARTED_PREDICATE";
public static final String SERVER_STOPPED_PREDICATE = "SERVER_STOPPED_PREDICATE";
public static final String SERVER_DELETED_PREDICATE = "SERVER_DELETED_PREDICATE";
public static final String SERVER_NORMAL_PREDICATE = "SERVER_NORMAL_PREDICATE";
public static final String VM_TOOLS_RUNNING_PREDICATE = "VM_TOOLS_RUNNING_PREDICATE";

@Override
protected void configure() {

}

@Provides
@Named(VLAN_DELETED_PREDICATE)
protected Predicate<String> provideVlanDeletedPredicate(final DimensionDataCloudControlApi api,
@Named(OPERATION_TIMEOUT) final Long operationTimeout, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new VlanState(api.getNetworkApi(), State.DELETED), operationTimeout, pollPeriod.pollInitialPeriod,
pollPeriod.pollMaxPeriod);
}

@Provides
@Named(VLAN_NORMAL_PREDICATE)
protected Predicate<String> provideVlanNormalPredicate(final DimensionDataCloudControlApi api,
@Named(OPERATION_TIMEOUT) final Long operationTimeout, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new VlanState(api.getNetworkApi(), State.NORMAL), operationTimeout, pollPeriod.pollInitialPeriod,
pollPeriod.pollMaxPeriod);
}

@Provides
@Named(NETWORK_DOMAIN_DELETED_PREDICATE)
protected Predicate<String> provideNetworkDomainDeletedPredicate(final DimensionDataCloudControlApi api,
@Named(OPERATION_TIMEOUT) final Long operationTimeout, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new NetworkDomainState(api.getNetworkApi(), State.DELETED), operationTimeout,
pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
}

@Provides
@Named(NETWORK_DOMAIN_NORMAL_PREDICATE)
protected Predicate<String> provideNetworkDomainNormalPredicate(final DimensionDataCloudControlApi api,
@Named(OPERATION_TIMEOUT) final Long operationTimeout, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new NetworkDomainState(api.getNetworkApi(), State.NORMAL), operationTimeout,
pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
}

@Provides
@Named(SERVER_STARTED_PREDICATE)
protected Predicate<String> provideServerStartedPredicate(final DimensionDataCloudControlApi api,
final ComputeServiceConstants.Timeouts timeouts, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new ServerStatus(api.getServerApi(), true, true), timeouts.nodeRunning, pollPeriod.pollInitialPeriod,
pollPeriod.pollMaxPeriod);
}

@Provides
@Named(SERVER_STOPPED_PREDICATE)
@VisibleForTesting
public Predicate<String> provideServerStoppedPredicate(final DimensionDataCloudControlApi api,
final ComputeServiceConstants.Timeouts timeouts, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new ServerStatus(api.getServerApi(), false, true), timeouts.nodeSuspended,
pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
}

@Provides
@Named(SERVER_DELETED_PREDICATE)
@VisibleForTesting
public Predicate<String> provideServerDeletedPredicate(final DimensionDataCloudControlApi api,
final ComputeServiceConstants.Timeouts timeouts, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new ServerState(api.getServerApi(), State.DELETED), timeouts.nodeTerminated,
pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
}

@Provides
@Named(SERVER_NORMAL_PREDICATE)
protected Predicate<String> provideServerNormalPredicate(final DimensionDataCloudControlApi api,
final ComputeServiceConstants.Timeouts timeouts, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new ServerState(api.getServerApi(), State.NORMAL), timeouts.nodeRunning,
pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod);
}

@Provides
@Named(VM_TOOLS_RUNNING_PREDICATE)
protected Predicate<String> provideVMToolsRunningPredicate(final DimensionDataCloudControlApi api,
@Named(OPERATION_TIMEOUT) final Long operationTimeout, final ComputeServiceConstants.PollPeriod pollPeriod) {
return retry(new VMToolsRunningStatus(api.getServerApi()), operationTimeout, pollPeriod.pollInitialPeriod,
pollPeriod.pollMaxPeriod);
}

private class VlanState implements Predicate<String> {

private final State state;
private final NetworkApi networkApi;

private VlanState(final NetworkApi networkApi, final State state) {
this.networkApi = networkApi;
this.state = state;
}

@Override
public boolean apply(final String vlanId) {
checkNotNull(vlanId, "vlanId");
logger.trace("looking for state on vlan %s", vlanId);
final Vlan vlan = networkApi.getVlan(vlanId);
final boolean isDeleted = (vlan == null) && (state == State.DELETED);
return isDeleted || ((vlan != null) && vlan.state() == state);
}
}

private class NetworkDomainState implements Predicate<String> {

private final State state;
private final NetworkApi networkApi;

private NetworkDomainState(final NetworkApi networkApi, final State state) {
this.networkApi = networkApi;
this.state = state;
}

@Override
public boolean apply(final String networkDomainId) {
checkNotNull(networkDomainId, "networkDomainId");
logger.trace("looking for state on network domain %s", networkDomainId);
final NetworkDomain networkDomain = networkApi.getNetworkDomain(networkDomainId);
final boolean isDeleted = networkDomain == null && state == State.DELETED;
return isDeleted || (networkDomain != null && networkDomain.state() == state);
}
}

private class ServerStatus implements Predicate<String> {

private final ServerApi api;
private final boolean started;
private final boolean deployed;

private ServerStatus(final ServerApi api, final boolean started, final boolean deployed) {
this.api = api;
this.started = started;
this.deployed = deployed;
}

@Override
public boolean apply(final String serverId) {
checkNotNull(serverId, "serverId");
logger.trace("looking for start status on Server %s", serverId);
final Server server = api.getServer(serverId);

// perhaps request isn't available, yet
if (server == null)
return false;
logger.trace("Looking for Server %s to be started: %s currently: %s", server.id(), started, server.started());
if (server.state().isFailed()) {
throw new IllegalStateException(String.format("Server %s is in FAILED state", server.id()));
}
return server.started() == started && server.deployed() == deployed;
}
}

private class ServerState implements Predicate<String> {

private final ServerApi api;
private final State state;

private ServerState(final ServerApi api, final State state) {
this.api = api;
this.state = state;
}

@Override
public boolean apply(final String serverId) {
checkNotNull(serverId, "serverId");
logger.trace("looking for state on Server %s", serverId);
final Server server = api.getServer(serverId);

if (server == null && state == State.DELETED) {
return true;
}

if (server.state().isFailed()) {
throw new IllegalStateException(String.format("Server %s is in FAILED state", server.id()));
} else {
return server.state() == state;
}
}
}

private class VMToolsRunningStatus implements Predicate<String> {

private final ServerApi api;

private VMToolsRunningStatus(final ServerApi api) {
this.api = api;
}

@Override
public boolean apply(final String serverId) {
checkNotNull(serverId, "serverId");
logger.trace("looking for guest tools state on Server %s", serverId);
final Server server = api.getServer(serverId);
if (server == null) {
throw new IllegalStateException(String.format("Server %s is not found", serverId));
}
final VmTools vmTools = server.guest().vmTools();
return vmTools != null && vmTools.runningStatus() == VmTools.RunningStatus.RUNNING;
}
}
}
@@ -0,0 +1,26 @@
/*
* 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.dimensiondata.cloudcontrol.config;

/**
* Configuration properties and constants used in Dimension Data Cloud Control connections.
*/
public class DimensionDataProperties {

public static final String OPERATION_TIMEOUT = "jclouds.dimensiondata.cloudcontrol.operation.timeout";
}

0 comments on commit 889b34b

Please sign in to comment.