Repository: jclouds-labs Updated Branches: refs/heads/2.0.x 6a25c7932 -> 0351481d9
Implement GetOrCreateNetworkDomainThenCreateNodes Strategy. Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/0351481d Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/0351481d Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/0351481d Branch: refs/heads/2.0.x Commit: 0351481d9ed3c33112efe91aa74ef875721af41f Parents: 6a25c79 Author: Trevor Flanagan <[email protected]> Authored: Wed Dec 20 17:22:58 2017 +0000 Committer: Ignasi Barrera <[email protected]> Committed: Fri Dec 22 09:04:29 2017 +0100 ---------------------------------------------------------------------- ...imensionDataCloudControlTemplateOptions.java | 153 ++++++++++++++++ ...GetOrCreateNetworkDomainThenCreateNodes.java | 177 ++++++++++++++++++ .../strategy/TemplateWithNetworkIds.java | 64 +++++++ ...sionDataCloudControlTemplateOptionsTest.java | 57 ++++++ ...rCreateNetworkDomainThenCreateNodesTest.java | 178 +++++++++++++++++++ 5 files changed, 629 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/0351481d/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptions.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptions.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptions.java new file mode 100644 index 0000000..0d40b38 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptions.java @@ -0,0 +1,153 @@ +/* + * 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.compute.options; + +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.javax.annotation.Nullable; + +public class DimensionDataCloudControlTemplateOptions extends TemplateOptions implements Cloneable { + + public static final String DEFAULT_NETWORK_DOMAIN_NAME = "JCLOUDS_NETWORK_DOMAIN"; + public static final String DEFAULT_VLAN_NAME = "JCLOUDS_VLAN"; + public static final String DEFAULT_PRIVATE_IPV4_BASE_ADDRESS = "10.0.0.0"; + public static final Integer DEFAULT_PRIVATE_IPV4_PREFIX_SIZE = 24; + + private String networkDomainName; + private String defaultPrivateIPv4BaseAddress; + private Integer defaultPrivateIPv4PrefixSize; + + public String getNetworkDomainName() { + return networkDomainName; + } + + public String getDefaultPrivateIPv4BaseAddress() { + return defaultPrivateIPv4BaseAddress; + } + + public Integer getDefaultPrivateIPv4PrefixSize() { + return defaultPrivateIPv4PrefixSize; + } + + public DimensionDataCloudControlTemplateOptions networkDomainName(@Nullable String networkDomainName) { + this.networkDomainName = networkDomainName; + return this; + } + + public DimensionDataCloudControlTemplateOptions defaultPrivateIPv4BaseAddress( + @Nullable String defaultPrivateIPv4BaseAddress) { + this.defaultPrivateIPv4BaseAddress = defaultPrivateIPv4BaseAddress; + return this; + } + + public DimensionDataCloudControlTemplateOptions defaultPrivateIPv4PrefixSize( + @Nullable Integer defaultPrivateIPv4PrefixSize) { + this.defaultPrivateIPv4PrefixSize = defaultPrivateIPv4PrefixSize; + return this; + } + + @Override + public DimensionDataCloudControlTemplateOptions clone() { + final DimensionDataCloudControlTemplateOptions options = new DimensionDataCloudControlTemplateOptions(); + copyTo(options); + return options; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DimensionDataCloudControlTemplateOptions)) { + return false; + } + if (!super.equals(o)) { + return false; + } + + DimensionDataCloudControlTemplateOptions that = (DimensionDataCloudControlTemplateOptions) o; + + if (networkDomainName != null ? + !networkDomainName.equals(that.networkDomainName) : + that.networkDomainName != null) { + return false; + } + + if (defaultPrivateIPv4BaseAddress != null ? + !defaultPrivateIPv4BaseAddress.equals(that.defaultPrivateIPv4BaseAddress) : + that.defaultPrivateIPv4BaseAddress != null) { + return false; + } + return defaultPrivateIPv4PrefixSize != null ? + defaultPrivateIPv4PrefixSize.equals(that.defaultPrivateIPv4PrefixSize) : + that.defaultPrivateIPv4PrefixSize == null; + + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (networkDomainName != null ? networkDomainName.hashCode() : 0); + result = 31 * result + (defaultPrivateIPv4BaseAddress != null ? defaultPrivateIPv4BaseAddress.hashCode() : 0); + result = 31 * result + (defaultPrivateIPv4PrefixSize != null ? defaultPrivateIPv4PrefixSize.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "DimensionDataCloudControlTemplateOptions{ networkDomainName='" + networkDomainName + + "', defaultPrivateIPv4BaseAddress='" + defaultPrivateIPv4BaseAddress + "', defaultPrivateIPv4PrefixSize='" + + defaultPrivateIPv4PrefixSize + "'}"; + } + + public static class Builder { + + /** + * @see #networkDomainName + */ + public static DimensionDataCloudControlTemplateOptions networkDomainName(final String networkDomainName) { + final DimensionDataCloudControlTemplateOptions options = new DimensionDataCloudControlTemplateOptions(); + return options.networkDomainName(networkDomainName); + } + + /** + * @see #defaultPrivateIPv4BaseAddress + */ + public static DimensionDataCloudControlTemplateOptions defaultPrivateIPv4BaseAddress( + final String defaultPrivateIPv4BaseAddress) { + final DimensionDataCloudControlTemplateOptions options = new DimensionDataCloudControlTemplateOptions(); + return options.defaultPrivateIPv4BaseAddress(defaultPrivateIPv4BaseAddress); + } + + /** + * @see #defaultPrivateIPv4PrefixSize + */ + public static DimensionDataCloudControlTemplateOptions defaultPrivateIPv4PrefixSize( + final Integer defaultPrivateIPv4PrefixSize) { + final DimensionDataCloudControlTemplateOptions options = new DimensionDataCloudControlTemplateOptions(); + return options.defaultPrivateIPv4PrefixSize(defaultPrivateIPv4PrefixSize); + } + + } + + /** + * {@inheritDoc} + */ + @Override + public DimensionDataCloudControlTemplateOptions nodeNames(Iterable<String> nodeNames) { + return DimensionDataCloudControlTemplateOptions.class.cast(super.nodeNames(nodeNames)); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/0351481d/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodes.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodes.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodes.java new file mode 100644 index 0000000..a427ed4 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodes.java @@ -0,0 +1,177 @@ +/* + * 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.compute.strategy; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.inject.Inject; +import org.jclouds.compute.config.CustomizationResponse; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; +import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; +import org.jclouds.compute.strategy.ListNodesStrategy; +import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi; +import org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions; +import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain; +import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan; + +import javax.inject.Named; +import javax.inject.Singleton; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.MoreObjects.firstNonNull; +import static java.lang.String.format; +import static org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions.DEFAULT_NETWORK_DOMAIN_NAME; +import static org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions.DEFAULT_VLAN_NAME; +import static org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlComputeServiceContextModule.NETWORK_DOMAIN_NORMAL_PREDICATE; +import static org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlComputeServiceContextModule.VLAN_NORMAL_PREDICATE; + +@Singleton +public class GetOrCreateNetworkDomainThenCreateNodes extends CreateNodesWithGroupEncodedIntoNameThenAddToSet { + + private final DimensionDataCloudControlApi api; + private final ComputeServiceConstants.Timeouts timeouts; + private final Predicate<String> networkDomainNormalPredicate; + private final Predicate<String> vlanNormalPredicate; + + @Inject + protected GetOrCreateNetworkDomainThenCreateNodes(final CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy, + final ListNodesStrategy listNodesStrategy, final GroupNamingConvention.Factory namingConvention, + final ListeningExecutorService userExecutor, + final CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, + final DimensionDataCloudControlApi api, final ComputeServiceConstants.Timeouts timeouts, + @Named(NETWORK_DOMAIN_NORMAL_PREDICATE) final Predicate<String> networkDomainNormalPredicate, + @Named(VLAN_NORMAL_PREDICATE) final Predicate<String> vlanNormalPredicate) { + super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, + customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); + this.api = api; + this.timeouts = timeouts; + this.networkDomainNormalPredicate = networkDomainNormalPredicate; + this.vlanNormalPredicate = vlanNormalPredicate; + } + + @Override + public Map<?, ListenableFuture<Void>> execute(final String group, final int count, final Template template, + final Set<NodeMetadata> goodNodes, final Map<NodeMetadata, Exception> badNodes, + final Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { + + final DimensionDataCloudControlTemplateOptions templateOptions = template.getOptions() + .as(DimensionDataCloudControlTemplateOptions.class); + + String networkDomainName = firstNonNull(templateOptions.getNetworkDomainName(), DEFAULT_NETWORK_DOMAIN_NAME); + String vlanName = firstNonNull( + templateOptions.getNetworks().isEmpty() ? null : templateOptions.getNetworks().iterator().next(), + DEFAULT_VLAN_NAME); + templateOptions.networkDomainName(networkDomainName); + String networkDomainId = tryCreateOrGetExistingNetworkDomainId(template.getLocation().getId(), networkDomainName); + String vlanId = tryCreateOrGetExistingVlanId(networkDomainId, vlanName, templateOptions); + templateOptions.networks(vlanName); + return super + .execute(group, count, new TemplateWithNetworkIds(template, networkDomainId, vlanId), goodNodes, badNodes, + customizationResponses); + } + + private String tryCreateOrGetExistingNetworkDomainId(final String datacenterId, final String networkDomainName) { + String networkDomainId = getExistingNetworkDomainId(datacenterId, networkDomainName).orNull(); + if (networkDomainId != null) { + logger.debug("Found a suitable existing network domain %s", networkDomainId); + } else { + networkDomainId = deployNeworkDomain(datacenterId, networkDomainName); + } + return networkDomainId; + } + + private String deployNeworkDomain(final String datacenter, final String networkDomainName) { + logger.debug("Creating a network domain '%s' in Datacenter '%s' ...", networkDomainName, datacenter); + String networkDomainId = api.getNetworkApi() + .deployNetworkDomain(datacenter, networkDomainName, "network domain created by jclouds", + NetworkDomain.Type.ESSENTIALS.name()); + String message = format("networkDomain(%s) is not ready within %d ms.", networkDomainId, timeouts.nodeRunning); + + if (!networkDomainNormalPredicate.apply(networkDomainId)) { + throw new IllegalStateException(message); + } + return networkDomainId; + } + + private Optional<String> getExistingNetworkDomainId(final String datacenterId, final String networkDomainName) { + Optional<NetworkDomain> networkDomainOptional = api.getNetworkApi() + .listNetworkDomainsWithDatacenterIdAndName(datacenterId, networkDomainName).concat().first(); + if (networkDomainOptional.isPresent()) { + return Optional.of(networkDomainOptional.get().id()); + } else { + return Optional.<String>absent(); + } + } + + private String tryCreateOrGetExistingVlanId(final String networkDomainId, final String vlanName, + final DimensionDataCloudControlTemplateOptions templateOptions) { + + String vlanId = getExistingVlan(networkDomainId, vlanName).orNull(); + if (vlanId != null) { + logger.debug("Found a suitable existing vlan %s", vlanId); + } else { + vlanId = deployVlan(networkDomainId, vlanName, templateOptions); + } + return vlanId; + + } + + private String deployVlan(final String networkDomainId, final String vlanName, + final DimensionDataCloudControlTemplateOptions templateOptions) { + logger.debug("Creating a vlan %s in network domain '%s' ...", vlanName, networkDomainId); + String defaultPrivateIPv4BaseAddress = firstNonNull(templateOptions.getDefaultPrivateIPv4BaseAddress(), + DimensionDataCloudControlTemplateOptions.DEFAULT_PRIVATE_IPV4_BASE_ADDRESS); + Integer defaultPrivateIPv4PrefixSize = firstNonNull(templateOptions.getDefaultPrivateIPv4PrefixSize(), + DimensionDataCloudControlTemplateOptions.DEFAULT_PRIVATE_IPV4_PREFIX_SIZE); + + String vlanId = api.getNetworkApi() + .deployVlan(networkDomainId, vlanName, "vlan created by jclouds", defaultPrivateIPv4BaseAddress, + defaultPrivateIPv4PrefixSize); + if (!vlanNormalPredicate.apply(vlanId)) { + String message = format("vlan(%s) is not ready within %d ms.", vlanId, timeouts.nodeRunning); + throw new IllegalStateException(message); + } + return vlanId; + } + + private Optional<String> getExistingVlan(final String networkDomainId, final String vlanName) { + FluentIterable<Vlan> vlans = api.getNetworkApi().listVlans(networkDomainId).concat(); + final Optional<Vlan> vlan = vlans.firstMatch(new Predicate<Vlan>() { + @Override + public boolean apply(final Vlan input) { + return input.name().equals(vlanName); + } + }); + + if (vlan.isPresent()) { + return Optional.of(vlan.get().id()); + } else { + return Optional.absent(); + } + } +} + http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/0351481d/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/TemplateWithNetworkIds.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/TemplateWithNetworkIds.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/TemplateWithNetworkIds.java new file mode 100644 index 0000000..496a652 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/TemplateWithNetworkIds.java @@ -0,0 +1,64 @@ +/* + * 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.compute.strategy; + +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.domain.Location; + +/** + * Extend the default {@link Template} object with extra identifier information about where the nodes must be created. + */ +public class TemplateWithNetworkIds implements Template { + + private final Template delegate; + private final String networkDomainId; + private final String vlanId; + + public TemplateWithNetworkIds(Template template, String networkDomainId, String vlanId) { + this.delegate = template; + this.networkDomainId = networkDomainId; + this.vlanId = vlanId; + } + + @Override + public Image getImage() { + return delegate.getImage(); + } + + @Override + public Hardware getHardware() { + return delegate.getHardware(); + } + + @Override + public Location getLocation() { + return delegate.getLocation(); + } + + @Override + public TemplateOptions getOptions() { + return delegate.getOptions(); + } + + @Override + public Template clone() { + return new TemplateWithNetworkIds(delegate.clone(), networkDomainId, vlanId); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/0351481d/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptionsTest.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptionsTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptionsTest.java new file mode 100644 index 0000000..02cfbc5 --- /dev/null +++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/options/DimensionDataCloudControlTemplateOptionsTest.java @@ -0,0 +1,57 @@ +/* + * 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.compute.options; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +@Test(groups = "unit", testName = "DimensionDataCloudControlTemplateOptionsTest") +public class DimensionDataCloudControlTemplateOptionsTest { + + private DimensionDataCloudControlTemplateOptions templateOptions; + private String networkDomainName; + private String defaultPrivateIPv4BaseAddress; + private int defaultPrivateIPv4PrefixSize; + + @BeforeMethod + public void setUp() throws Exception { + networkDomainName = "networkDomainName"; + defaultPrivateIPv4BaseAddress = "defaultPrivateIPv4BaseAddress"; + defaultPrivateIPv4PrefixSize = 100; + templateOptions = DimensionDataCloudControlTemplateOptions.Builder.networkDomainName(networkDomainName) + .defaultPrivateIPv4BaseAddress(defaultPrivateIPv4BaseAddress) + .defaultPrivateIPv4PrefixSize(defaultPrivateIPv4PrefixSize); + } + + @Test + public void testBuilder() throws Exception { + assertEquals(networkDomainName, templateOptions.getNetworkDomainName()); + assertEquals(defaultPrivateIPv4BaseAddress, templateOptions.getDefaultPrivateIPv4BaseAddress()); + assertEquals(defaultPrivateIPv4PrefixSize, templateOptions.getDefaultPrivateIPv4PrefixSize().intValue()); + } + + @Test + public void testEquals() throws Exception { + assertTrue(templateOptions.equals( + DimensionDataCloudControlTemplateOptions.Builder.networkDomainName(networkDomainName) + .defaultPrivateIPv4BaseAddress(defaultPrivateIPv4BaseAddress) + .defaultPrivateIPv4PrefixSize(defaultPrivateIPv4PrefixSize))); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/0351481d/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodesTest.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodesTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodesTest.java new file mode 100644 index 0000000..0fef94d --- /dev/null +++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/compute/strategy/GetOrCreateNetworkDomainThenCreateNodesTest.java @@ -0,0 +1,178 @@ +/* + * 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.compute.strategy; + +import com.google.common.base.Predicate; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.ListeningExecutorService; +import org.easymock.EasyMock; +import org.jclouds.collect.IterableWithMarkers; +import org.jclouds.collect.PagedIterables; +import org.jclouds.compute.config.CustomizationResponse; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; +import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; +import org.jclouds.compute.strategy.ListNodesStrategy; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi; +import org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions; +import org.jclouds.dimensiondata.cloudcontrol.domain.IpRange; +import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain; +import org.jclouds.dimensiondata.cloudcontrol.domain.State; +import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan; +import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi; +import org.jclouds.domain.Location; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.Date; + +import static org.easymock.EasyMock.createNiceMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMockSupport.injectMocks; +import static org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions.DEFAULT_NETWORK_DOMAIN_NAME; +import static org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions.DEFAULT_PRIVATE_IPV4_BASE_ADDRESS; +import static org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions.DEFAULT_PRIVATE_IPV4_PREFIX_SIZE; +import static org.jclouds.dimensiondata.cloudcontrol.compute.options.DimensionDataCloudControlTemplateOptions.DEFAULT_VLAN_NAME; +import static org.testng.AssertJUnit.assertEquals; + +@Test(groups = "unit", testName = "GetOrCreateNetworkDomainThenCreateNodesTest") +public class GetOrCreateNetworkDomainThenCreateNodesTest { + + private GetOrCreateNetworkDomainThenCreateNodes getOrCreateNetworkDomainThenCreateNodes; + private NetworkApi networkApi; + private DimensionDataCloudControlApi api; + private Template template; + private DimensionDataCloudControlTemplateOptions templateOptions; + private CreateNodeWithGroupEncodedIntoName addNodeWithGroupStrategy; + private ListNodesStrategy listNodesStrategy; + private GroupNamingConvention.Factory namingConvention; + private ListeningExecutorService userExecutor; + private CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory; + private org.jclouds.compute.reference.ComputeServiceConstants.Timeouts timeouts; + private Location location; + private String datacenterId; + private NetworkDomain networkDomain; + private Vlan vlan; + + @BeforeMethod + public void setUp() throws Exception { + networkApi = EasyMock.createMock(NetworkApi.class); + api = EasyMock.createMock(DimensionDataCloudControlApi.class); + template = EasyMock.createNiceMock(Template.class); + addNodeWithGroupStrategy = EasyMock.createNiceMock(CreateNodeWithGroupEncodedIntoName.class); + listNodesStrategy = EasyMock.createNiceMock(ListNodesStrategy.class); + namingConvention = EasyMock.createNiceMock(GroupNamingConvention.Factory.class); + userExecutor = EasyMock.createNiceMock(ListeningExecutorService.class); + customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory = EasyMock + .createNiceMock(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class); + location = createNiceMock(Location.class); + templateOptions = new DimensionDataCloudControlTemplateOptions(); + templateOptions.nodeNames(Sets.newHashSet("node1")); + datacenterId = "datacenterId"; + + timeouts = new ComputeServiceConstants.Timeouts(); + + final Predicate<String> alwaysTrue = new Predicate<String>() { + @Override + public boolean apply(final String input) { + return true; + } + }; + + getOrCreateNetworkDomainThenCreateNodes = new GetOrCreateNetworkDomainThenCreateNodes(addNodeWithGroupStrategy, + listNodesStrategy, namingConvention, userExecutor, + customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, api, timeouts, alwaysTrue, alwaysTrue); + + networkDomain = NetworkDomain.builder().id("690de302-bb80-49c6-b401-8c02bbefb945") + .name(DEFAULT_NETWORK_DOMAIN_NAME).build(); + vlan = Vlan.builder().networkDomain(networkDomain).id("vlanId").name(DEFAULT_VLAN_NAME).description("") + .privateIpv4Range(IpRange.create("10.0.0.0", 24)) + .ipv6Range(IpRange.create("2607:f480:111:1575:0:0:0:0", 64)).ipv4GatewayAddress("10.0.0.1") + .ipv6GatewayAddress("2607:f480:111:1575:0:0:0:1").createTime(new Date()).state(State.NORMAL) + .datacenterId("NA9").build(); + + injectMocks(api); + injectMocks(template); + injectMocks(networkApi); + expect(template.getOptions()).andReturn(templateOptions).anyTimes(); + expect(template.getLocation()).andReturn(location); + expect(location.getId()).andReturn(datacenterId); + + expect(api.getNetworkApi()).andReturn(networkApi).anyTimes(); + } + + @Test + public void testExecute() throws Exception { + expect(networkApi.listNetworkDomainsWithDatacenterIdAndName(datacenterId, DEFAULT_NETWORK_DOMAIN_NAME)) + .andReturn(PagedIterables.onlyPage(IterableWithMarkers.from(Lists.newArrayList(networkDomain)))); + + expect(networkApi.listVlans(networkDomain.id())) + .andReturn(PagedIterables.onlyPage(IterableWithMarkers.from(Lists.newArrayList(vlan)))); + + replay(networkApi, api, template, location); + + executeAndAssert(); + } + + @Test(dependsOnMethods = "testExecute") + public void testExecute_deployNetworkDomain_deployVlan() throws Exception { + expect(networkApi.listNetworkDomainsWithDatacenterIdAndName(datacenterId, DEFAULT_NETWORK_DOMAIN_NAME)) + .andReturn(PagedIterables.onlyPage(IterableWithMarkers.from(Lists.<NetworkDomain>newArrayList()))); + + final String deployedNetworkDomainId = "deployedNetworkDomainId"; + final String networkDomainDescription = "network domain created by jclouds"; + + final NetworkDomain deployedNetworkDomain = NetworkDomain.builder().id(deployedNetworkDomainId) + .description(networkDomainDescription).name(DEFAULT_NETWORK_DOMAIN_NAME).state(State.NORMAL).build(); + expect(networkApi.deployNetworkDomain(datacenterId, DEFAULT_NETWORK_DOMAIN_NAME, networkDomainDescription, + NetworkDomain.Type.ESSENTIALS.name())).andReturn(deployedNetworkDomainId); + expect(networkApi.getNetworkDomain(deployedNetworkDomainId)).andReturn(deployedNetworkDomain); + + final String deployedVlanId = "deployedVlanId"; + final String deployedVlanDescription = "vlan created by jclouds"; + Vlan deployedVlan = Vlan.builder().networkDomain(deployedNetworkDomain).id("deployedVlanId") + .name(DEFAULT_VLAN_NAME).description("").privateIpv4Range(IpRange.create("10.0.0.0", 24)) + .ipv6Range(IpRange.create("2607:f480:111:1575:0:0:0:0", 64)).ipv4GatewayAddress("10.0.0.1") + .ipv6GatewayAddress("2607:f480:111:1575:0:0:0:1").createTime(new Date()).state(State.NORMAL) + .datacenterId(datacenterId).build(); + expect(networkApi.listVlans(deployedNetworkDomain.id())) + .andReturn(PagedIterables.onlyPage(IterableWithMarkers.from(Lists.<Vlan>newArrayList()))); + expect(networkApi.deployVlan(deployedNetworkDomainId, DEFAULT_VLAN_NAME, deployedVlanDescription, + DEFAULT_PRIVATE_IPV4_BASE_ADDRESS, DEFAULT_PRIVATE_IPV4_PREFIX_SIZE)).andReturn(deployedVlanId); + expect(networkApi.getVlan(deployedVlanId)).andReturn(deployedVlan); + + replay(networkApi, api, template, location); + + executeAndAssert(); + } + + private void executeAndAssert() { + getOrCreateNetworkDomainThenCreateNodes.execute("group", 0, template, Collections.<NodeMetadata>emptySet(), + Collections.<NodeMetadata, Exception>emptyMap(), + ArrayListMultimap.<NodeMetadata, CustomizationResponse>create()); + + assertEquals(DEFAULT_NETWORK_DOMAIN_NAME, templateOptions.getNetworkDomainName()); + assertEquals(DEFAULT_VLAN_NAME, templateOptions.getNetworks().iterator().next()); + } +}
