From 7a9f10f4420d4609da2636b5aa6ea545bccc7942 Mon Sep 17 00:00:00 2001 From: Andrew Donald Kennedy Date: Sun, 1 May 2011 17:40:55 +0100 Subject: [PATCH] Add IpType config option for GoGrid --- .../GoGridBindComputeStrategiesByClass.java | 6 +- .../options/GoGridTemplateOptions.java | 253 ++++++++++++++++++ ....java => FindIpThenCreateNodeInGroup.java} | 34 ++- 3 files changed, 275 insertions(+), 18 deletions(-) create mode 100644 providers/gogrid/src/main/java/org/jclouds/gogrid/compute/options/GoGridTemplateOptions.java rename providers/gogrid/src/main/java/org/jclouds/gogrid/compute/strategy/{FindPublicIpThenCreateNodeInGroup.java => FindIpThenCreateNodeInGroup.java} (81%) diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridBindComputeStrategiesByClass.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridBindComputeStrategiesByClass.java index 2f34306fc0..b45d6c92ec 100644 --- a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridBindComputeStrategiesByClass.java +++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridBindComputeStrategiesByClass.java @@ -26,21 +26,19 @@ import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.SuspendNodeStrategy; -import org.jclouds.gogrid.compute.strategy.FindPublicIpThenCreateNodeInGroup; +import org.jclouds.gogrid.compute.strategy.FindIpThenCreateNodeInGroup; import org.jclouds.gogrid.compute.strategy.GoGridDestroyNodeStrategy; import org.jclouds.gogrid.compute.strategy.GoGridGetNodeMetadataStrategy; import org.jclouds.gogrid.compute.strategy.GoGridLifeCycleStrategy; import org.jclouds.gogrid.compute.strategy.GoGridListNodesStrategy; /** - * * @author Adrian Cole - * */ public class GoGridBindComputeStrategiesByClass extends BindComputeStrategiesByClass { @Override protected Class defineAddNodeWithTagStrategy() { - return FindPublicIpThenCreateNodeInGroup.class; + return FindIpThenCreateNodeInGroup.class; } @Override diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/options/GoGridTemplateOptions.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/options/GoGridTemplateOptions.java new file mode 100644 index 0000000000..a1b76dbdb5 --- /dev/null +++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/options/GoGridTemplateOptions.java @@ -0,0 +1,253 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.gogrid.compute.options; + +import java.util.Arrays; + +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.gogrid.domain.IpType; +import org.jclouds.io.Payload; + +/** + * Contains options supported in the {@code ComputeService#runNode} operation on the "gogrid" + * provider. + * + *

Usage

+ * The recommended way to instantiate a {@link GoGridTemplateOptions} object is to statically + * import {@code GoGridTemplateOptions.*} and invoke a static creation method followed by an + * instance mutator (if needed): + *

+ * + * import static org.jclouds.compute.options.GoGridTemplateOptions.Builder.*; + * ComputeService client = // get connection + * templateBuilder.options(inboundPorts(22, 80, 8080, 443)); + * Set set = client.runNodesWithTag(tag, 2, templateBuilder.build()); + * + * + * @author Adrian Cole + * @author Andrew Kennedy + */ +public class GoGridTemplateOptions extends TemplateOptions implements Cloneable { + @Override + public GoGridTemplateOptions clone() { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + copyTo(options); + return options; + } + + @Override + public void copyTo(TemplateOptions to) { + super.copyTo(to); + if (to instanceof GoGridTemplateOptions) { + GoGridTemplateOptions eTo = GoGridTemplateOptions.class.cast(to); + if (getIpType() != null) + eTo.ipType(getIpType()); + } + } + + private IpType ipType = null; + + public static final GoGridTemplateOptions NONE = new GoGridTemplateOptions(); + + /** + * Specifies the ipType used for network interfaces on the VMs + */ + public GoGridTemplateOptions ipType(IpType ipType) { + this.ipType = ipType; + return this; + } + + public static class Builder { + /** + * @see GoGridTemplateOptions#ipAddressAllocationMode + */ + public static GoGridTemplateOptions ipType(IpType ipType) { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + return GoGridTemplateOptions.class.cast(options.ipType(ipType)); + } + + // methods that only facilitate returning the correct object type + /** + * @see TemplateOptions#inboundPorts + */ + public static GoGridTemplateOptions inboundPorts(int... ports) { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + return GoGridTemplateOptions.class.cast(options.inboundPorts(ports)); + } + + /** + * @see TemplateOptions#port + */ + public static GoGridTemplateOptions blockOnPort(int port, int seconds) { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + return GoGridTemplateOptions.class.cast(options.blockOnPort(port, seconds)); + } + + /** + * @see TemplateOptions#runScript + */ + public static GoGridTemplateOptions runScript(Payload script) { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + return GoGridTemplateOptions.class.cast(options.runScript(script)); + } + + /** + * @see TemplateOptions#installPrivateKey + */ + public static GoGridTemplateOptions installPrivateKey(Payload rsaKey) { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + return GoGridTemplateOptions.class.cast(options.installPrivateKey(rsaKey)); + } + + /** + * @see TemplateOptions#authorizePublicKey + */ + public static GoGridTemplateOptions authorizePublicKey(Payload rsaKey) { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + return GoGridTemplateOptions.class.cast(options.authorizePublicKey(rsaKey)); + } + + /** + * @see TemplateOptions#withDetails + */ + public static GoGridTemplateOptions withDetails() { + GoGridTemplateOptions options = new GoGridTemplateOptions(); + return GoGridTemplateOptions.class.cast(options.withMetadata()); + } + } + + /** + * @return ipType on the vms + */ + public IpType getIpType() { + return ipType; + } + + // methods that only facilitate returning the correct object type + + /** + * @see TemplateOptions#blockOnPort + */ + @Override + public GoGridTemplateOptions blockOnPort(int port, int seconds) { + return GoGridTemplateOptions.class.cast(super.blockOnPort(port, seconds)); + } + + /** + * + * special thing is that we do assume if you are passing groups that you have everything you need + * already defined. for example, our option inboundPorts normally creates ingress rules + * accordingly but if we notice you've specified securityGroups, we do not mess with rules at all + * + * @see TemplateOptions#inboundPorts + */ + @Override + public GoGridTemplateOptions inboundPorts(int... ports) { + return GoGridTemplateOptions.class.cast(super.inboundPorts(ports)); + } + + /** + * @see TemplateOptions#authorizePublicKey(String) + */ + @Override + public GoGridTemplateOptions authorizePublicKey(String publicKey) { + return GoGridTemplateOptions.class.cast(super.authorizePublicKey(publicKey)); + } + + /** + * @see TemplateOptions#authorizePublicKey(Payload) + */ + @Override + @Deprecated + public GoGridTemplateOptions authorizePublicKey(Payload publicKey) { + return GoGridTemplateOptions.class.cast(super.authorizePublicKey(publicKey)); + } + + /** + * @see TemplateOptions#installPrivateKey(String) + */ + @Override + public GoGridTemplateOptions installPrivateKey(String privateKey) { + return GoGridTemplateOptions.class.cast(super.installPrivateKey(privateKey)); + } + + /** + * @see TemplateOptions#installPrivateKey(Payload) + */ + @Override + @Deprecated + public GoGridTemplateOptions installPrivateKey(Payload privateKey) { + return GoGridTemplateOptions.class.cast(super.installPrivateKey(privateKey)); + } + + /** + * @see TemplateOptions#runScript(Payload) + */ + @Override + public GoGridTemplateOptions runScript(Payload script) { + return GoGridTemplateOptions.class.cast(super.runScript(script)); + } + + /** + * @see TemplateOptions#runScript(byte[]) + */ + @Override + @Deprecated + public GoGridTemplateOptions runScript(byte[] script) { + return GoGridTemplateOptions.class.cast(super.runScript(script)); + } + + /** + * @see TemplateOptions#withMetadata + */ + @Override + public GoGridTemplateOptions withMetadata() { + return GoGridTemplateOptions.class.cast(super.withMetadata()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((ipType == null) ? 0 : ipType.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + GoGridTemplateOptions other = (GoGridTemplateOptions) obj; + if (ipType != other.ipType) + return false; + return true; + } + + @Override + public String toString() { + return "[" + (ipType != null ? "ipType=" + ipType : "") + ", inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + + (privateKey != null) + ", publicKey=" + (publicKey != null) + ", runScript=" + (script != null) + + ", port:seconds=" + port + ":" + seconds + ", metadata/details: " + includeMetadata + "]"; + } + +} diff --git a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/strategy/FindPublicIpThenCreateNodeInGroup.java b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/strategy/FindIpThenCreateNodeInGroup.java similarity index 81% rename from providers/gogrid/src/main/java/org/jclouds/gogrid/compute/strategy/FindPublicIpThenCreateNodeInGroup.java rename to providers/gogrid/src/main/java/org/jclouds/gogrid/compute/strategy/FindIpThenCreateNodeInGroup.java index f71d330178..a778a70e43 100644 --- a/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/strategy/FindPublicIpThenCreateNodeInGroup.java +++ b/providers/gogrid/src/main/java/org/jclouds/gogrid/compute/strategy/FindIpThenCreateNodeInGroup.java @@ -18,7 +18,7 @@ */ package org.jclouds.gogrid.compute.strategy; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.*; import java.security.SecureRandom; import java.util.Set; @@ -26,12 +26,13 @@ import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; -import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.Template; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; import org.jclouds.gogrid.GoGridClient; +import org.jclouds.gogrid.compute.options.GoGridTemplateOptions; import org.jclouds.gogrid.domain.Ip; import org.jclouds.gogrid.domain.IpType; import org.jclouds.gogrid.domain.PowerCommand; @@ -48,22 +49,23 @@ import com.google.common.collect.Iterables; * @author Oleksiy Yarmula */ @Singleton -public class FindPublicIpThenCreateNodeInGroup implements CreateNodeWithGroupEncodedIntoName { +public class FindIpThenCreateNodeInGroup implements CreateNodeWithGroupEncodedIntoName { private final GoGridClient client; private final Function sizeToRam; private final Function serverToNodeMetadata; private RetryablePredicate serverLatestJobCompleted; private RetryablePredicate serverLatestJobCompletedShort; - + @Inject - protected FindPublicIpThenCreateNodeInGroup(GoGridClient client, + protected FindIpThenCreateNodeInGroup(GoGridClient client, Function serverToNodeMetadata, Function sizeToRam, Timeouts timeouts) { this.client = client; this.serverToNodeMetadata = serverToNodeMetadata; this.sizeToRam = sizeToRam; - this.serverLatestJobCompleted = new RetryablePredicate(new ServerLatestJobCompleted( - client.getJobServices()), timeouts.nodeRunning * 9l / 10l); + this.serverLatestJobCompleted = new RetryablePredicate( + new ServerLatestJobCompleted(client.getJobServices()), + timeouts.nodeRunning * 9l / 10l); this.serverLatestJobCompletedShort = new RetryablePredicate( new ServerLatestJobCompleted(client.getJobServices()), timeouts.nodeRunning * 1l / 10l); @@ -74,15 +76,19 @@ public class FindPublicIpThenCreateNodeInGroup implements CreateNodeWithGroupEnc Server addedServer = null; boolean notStarted = true; int numOfRetries = 20; + GetIpListOptions unassignedIps = new GetIpListOptions() + .onlyUnassigned() + .inDatacenter(template.getLocation().getId()); + if (template.getOptions() instanceof GoGridTemplateOptions) { + IpType ipType = GoGridTemplateOptions.class.cast(template.getOptions()).getIpType(); + unassignedIps = unassignedIps.onlyWithType(ipType); + } // lock-free consumption of a shared resource: IP address pool while (notStarted) { // TODO: replace with Predicate-based thread - // collision avoidance for - // simplicity - Set availableIps = client.getIpServices().getIpList( - new GetIpListOptions().onlyUnassigned().onlyWithType(IpType.PUBLIC).inDatacenter( - template.getLocation().getId())); - if (availableIps.size() == 0) - throw new RuntimeException("No public IPs available on this identity."); + // collision avoidance for simplicity + Set availableIps = client.getIpServices().getIpList(unassignedIps); + if (availableIps.isEmpty()) + throw new RuntimeException("No IPs available on this identity."); int ipIndex = new SecureRandom().nextInt(availableIps.size()); Ip availableIp = Iterables.get(availableIps, ipIndex); try {