Removing network management, use default network, use fewer firewalls.

This commit is contained in:
Daniel Broudy 2015-04-23 13:39:03 -07:00 committed by Ignasi Barrera
parent 9d3b2d70e1
commit 5adfce8d48
22 changed files with 258 additions and 569 deletions

View File

@ -58,7 +58,6 @@ import org.jclouds.domain.Location;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
import org.jclouds.googlecomputeengine.domain.Firewall;
import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.features.FirewallApi;
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
@ -125,36 +124,26 @@ public final class GoogleComputeEngineService extends BaseComputeService {
protected synchronized void cleanUpIncidentalResourcesOfDeadNodes(Set<? extends NodeMetadata> deadNodes) {
Set<String> orphanedGroups = findOrphanedGroups.apply(deadNodes);
for (String orphanedGroup : orphanedGroups) {
cleanUpNetworksAndFirewallsForGroup(orphanedGroup);
cleanUpFirewallsForGroup(orphanedGroup);
}
}
private void cleanUpNetworksAndFirewallsForGroup(final String groupName) {
String resourceName = namingConvention.create().sharedNameForGroup(groupName);
Network network = api.networks().get(resourceName);
private void cleanUpFirewallsForGroup(final String groupName) {
GroupNamingConvention namingScheme = namingConvention.create();
FirewallApi firewallApi = api.firewalls();
for (Firewall firewall : concat(firewallApi.list())) {
if (firewall == null || !firewall.network().equals(network.selfLink())) {
continue;
String foundGroup = namingScheme.groupInUniqueNameOrNull(firewall.name());
if ((foundGroup != null) && foundGroup.equals(groupName)){
AtomicReference<Operation> operation = Atomics.newReference(firewallApi.delete(firewall.name()));
operationDone.apply(operation);
if (operation.get().httpErrorStatusCode() != null) {
logger.warn("delete orphaned firewall %s failed. Http Error Code: %d HttpError: %s",
operation.get().targetId(), operation.get().httpErrorStatusCode(),
operation.get().httpErrorMessage());
}
}
AtomicReference<Operation> operation = Atomics.newReference(firewallApi.delete(firewall.name()));
operationDone.apply(operation);
if (operation.get().httpErrorStatusCode() != null) {
logger.warn("delete orphaned firewall %s failed. Http Error Code: %d HttpError: %s",
operation.get().targetId(), operation.get().httpErrorStatusCode(),
operation.get().httpErrorMessage());
}
}
AtomicReference<Operation> operation = Atomics.newReference(api.networks().delete(resourceName));
operationDone.apply(operation);
if (operation.get().httpErrorStatusCode() != null) {
logger.warn("delete orphaned network failed. Http Error Code: " + operation.get().httpErrorStatusCode() +
" HttpError: " + operation.get().httpErrorMessage());
}
}

View File

@ -23,8 +23,10 @@ import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
import static org.jclouds.googlecloud.internal.ListPages.concat;
import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.IMAGE_PROJECTS;
import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.simplifyPorts;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@ -111,26 +113,35 @@ public final class GoogleComputeEngineServiceAdapter
@Override public NodeAndInitialCredentials<Instance> createNodeWithGroupEncodedIntoName(String group, String name,
Template template) {
GoogleComputeEngineTemplateOptions options = GoogleComputeEngineTemplateOptions.class.cast(template.getOptions());
checkNotNull(options.network(), "template options must specify a network");
checkNotNull(options.getNetworks(), "template options must specify a network");
checkNotNull(template.getHardware().getUri(), "hardware must have a URI");
checkNotNull(template.getImage().getUri(), "image URI is null");
List<AttachDisk> disks = Lists.newArrayList();
disks.add(AttachDisk.newBootDisk(template.getImage().getUri()));
Iterator<String> networks = options.getNetworks().iterator();
URI network = URI.create(networks.next());
assert !networks.hasNext() : "Error: Options should specify only one network";
NewInstance newInstance = NewInstance.create(
name, // name
template.getHardware().getUri(), // machineType
options.network(), // network
network, // network
disks, // disks
group // description
);
// Add tags from template and for security groups
// Add tags from template
newInstance.tags().items().addAll(options.getTags());
// Add tags for firewalls
FirewallTagNamingConvention naming = firewallTagNamingConvention.get(group);
for (int port : options.getInboundPorts()) {
newInstance.tags().items().add(naming.name(port));
List<String> ports = simplifyPorts(options.getInboundPorts());
if (ports != null){
newInstance.tags().items().add(naming.name(ports));
}
// Add metadata from template and for ssh key and image id

View File

@ -45,9 +45,6 @@ import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location;
import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineService;
import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineServiceAdapter;
import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
import org.jclouds.googlecomputeengine.compute.functions.CreateNetworkIfNeeded;
import org.jclouds.googlecomputeengine.compute.functions.FindNetworkOrCreate;
import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention;
import org.jclouds.googlecomputeengine.compute.functions.GoogleComputeEngineImageToImage;
import org.jclouds.googlecomputeengine.compute.functions.InstanceToNodeMetadata;
@ -62,7 +59,6 @@ import org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEnco
import org.jclouds.googlecomputeengine.domain.Image;
import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.MachineType;
import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.location.suppliers.ImplicitLocationSupplier;
import org.jclouds.location.suppliers.implicit.FirstZone;
@ -72,9 +68,6 @@ import com.google.common.base.Functions;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.Injector;
@ -121,12 +114,6 @@ public final class GoogleComputeEngineServiceContextModule
bind(new TypeLiteral<Predicate<String>>() {
}).to(AllNodesInGroupTerminated.class);
bind(new TypeLiteral<Function<NetworkAndAddressRange, Network>>() {
}).to(CreateNetworkIfNeeded.class);
bind(new TypeLiteral<CacheLoader<NetworkAndAddressRange, Network>>() {
}).to(FindNetworkOrCreate.class);
bind(FirewallTagNamingConvention.Factory.class).in(Scopes.SINGLETON);
bindHttpApi(binder(), Resources.class);
}
@ -173,11 +160,6 @@ public final class GoogleComputeEngineServiceContextModule
}, seconds, SECONDS);
}
@Provides @Singleton
LoadingCache<NetworkAndAddressRange, Network> networkMap(CacheLoader<NetworkAndAddressRange, Network> in) {
return CacheBuilder.newBuilder().build(in);
}
@Override protected Optional<ImageExtension> provideImageExtension(Injector i) {
return Optional.absent();
}

View File

@ -1,41 +0,0 @@
/*
* 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.googlecomputeengine.compute.domain;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
/** Container for network, IPv4 range and optional gateway, for creation caching */
@AutoValue
public abstract class NetworkAndAddressRange {
public abstract String name();
public abstract String rangeIPv4();
@Nullable public abstract String gateway();
@SerializedNames({ "name", "ipV4Range", "gateway" })
public static NetworkAndAddressRange create(String name, String rangeIPv4, @Nullable String gateway) {
return new AutoValue_NetworkAndAddressRange(name, rangeIPv4, gateway);
}
NetworkAndAddressRange() {
}
}

View File

@ -1,74 +0,0 @@
/*
* 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.googlecomputeengine.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.options.NetworkCreationOptions;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.util.concurrent.Atomics;
public final class CreateNetworkIfNeeded implements Function<NetworkAndAddressRange, Network> {
private final GoogleComputeEngineApi api;
private final Predicate<AtomicReference<Operation>> operationDone;
@Inject CreateNetworkIfNeeded(GoogleComputeEngineApi api, Predicate<AtomicReference<Operation>> operationDone) {
this.api = api;
this.operationDone = operationDone;
}
@Override
public Network apply(NetworkAndAddressRange input) {
checkNotNull(input, "input");
Network nw = api.networks().get(input.name());
if (nw != null) {
return nw;
}
if (input.gateway() != null) {
NetworkCreationOptions options = new NetworkCreationOptions.Builder(input.name(), input.rangeIPv4())
.gatewayIPv4(input.gateway()).build();
AtomicReference<Operation> operation = Atomics.newReference(api.networks()
.createInIPv4Range(options));
operationDone.apply(operation);
checkState(operation.get().httpErrorStatusCode() == null,
"Could not insert network, operation failed" + operation);
} else {
AtomicReference<Operation> operation = Atomics
.newReference(api.networks().createInIPv4Range(input.name(), input.rangeIPv4()));
operationDone.apply(operation);
checkState(operation.get().httpErrorStatusCode() == null,
"Could not insert network, operation failed" + operation);
}
return checkNotNull(api.networks().get(input.name()), "no network with name %s was found",
input.name());
}
}

View File

@ -1,45 +0,0 @@
/*
* 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.googlecomputeengine.compute.functions;
import javax.inject.Inject;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
import org.jclouds.googlecomputeengine.domain.Network;
import com.google.common.base.Function;
import com.google.common.cache.CacheLoader;
public final class FindNetworkOrCreate extends CacheLoader<NetworkAndAddressRange, Network> {
private final GoogleComputeEngineApi api;
private final Function<NetworkAndAddressRange, Network> networkCreator;
@Inject FindNetworkOrCreate(GoogleComputeEngineApi api, Function<NetworkAndAddressRange, Network> networkCreator) {
this.api = api;
this.networkCreator = networkCreator;
}
@Override public Network load(NetworkAndAddressRange in) {
Network network = api.networks().get(in.name());
if (network != null) {
return network;
} else {
return networkCreator.apply(in);
}
}
}

View File

@ -16,6 +16,8 @@
*/
package org.jclouds.googlecomputeengine.compute.functions;
import java.util.List;
import javax.inject.Inject;
import org.jclouds.compute.functions.GroupNamingConvention;
@ -46,10 +48,18 @@ public final class FirewallTagNamingConvention {
this.sharedResourceName = sharedResourceName;
}
public String name(int port) {
return String.format("%s-port-%s", sharedResourceName, port);
public String name(List<String> ports) {
final int prime = 31;
int result = 1;
for (String s : ports){
result = result * prime + s.hashCode();
// TODO(broudy): this may break between java versions! Consider a different implementation.
}
return String.format("%s-%s", sharedResourceName, Integer.toHexString(result));
}
public Predicate<String> isFirewallTag() {
return new Predicate<String>() {
@Override

View File

@ -89,7 +89,6 @@ public final class InstanceToNodeMetadata implements Function<Instance, NodeMeta
URI bootImage = diskToSourceImage.get(input.disks().get(0).source());
builder.id(input.selfLink().toString())
.providerId(input.id())
.name(input.name())
.providerId(input.id())
.hostname(input.name())

View File

@ -16,18 +16,15 @@
*/
package org.jclouds.googlecomputeengine.compute.options;
import java.net.URI;
import java.util.Map;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.scriptbuilder.domain.Statement;
/** Instance options specific to Google Compute Engine. */
public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
private URI network = null;
private boolean autoCreateKeyPair = true;
@Override
@ -42,22 +39,10 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
super.copyTo(to);
if (to instanceof GoogleComputeEngineTemplateOptions) {
GoogleComputeEngineTemplateOptions eTo = GoogleComputeEngineTemplateOptions.class.cast(to);
eTo.network(network());
eTo.autoCreateKeyPair(autoCreateKeyPair());
}
}
/** @see #network() */
public GoogleComputeEngineTemplateOptions network(URI network) {
this.network = network;
return this;
}
/** The network instances will attach to. When absent, a new network will be created for the project. */
@Nullable public URI network() {
return network;
}
/**
* Sets whether an SSH key pair should be created automatically.
*/

View File

@ -16,10 +16,13 @@
*/
package org.jclouds.googlecomputeengine.compute.strategy;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.of;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -39,7 +42,6 @@ import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention;
import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
import org.jclouds.googlecomputeengine.domain.Firewall;
@ -53,9 +55,8 @@ import org.jclouds.ssh.SshKeyPairGenerator;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.Atomics;
import com.google.common.util.concurrent.ListenableFuture;
@ -67,8 +68,9 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
public static final String EXTERIOR_RANGE = "0.0.0.0/0";
public static final String DEFAULT_INTERNAL_NETWORK_RANGE = "10.0.0.0/8";
public static final String DEFAULT_NETWORK_NAME = "default";
private final GoogleComputeEngineApi api;
private final LoadingCache<NetworkAndAddressRange, Network> networkMap;
private final Predicate<AtomicReference<Operation>> operationDone;
private final FirewallTagNamingConvention.Factory firewallTagNamingConvention;
private final SshKeyPairGenerator keyGenerator;
@ -85,13 +87,11 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
GoogleComputeEngineApi api, Predicate<AtomicReference<Operation>> operationDone,
LoadingCache<NetworkAndAddressRange, Network> networkMap,
FirewallTagNamingConvention.Factory firewallTagNamingConvention, SshKeyPairGenerator keyGenerator) {
super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
this.api = api;
this.operationDone = operationDone;
this.networkMap = networkMap;
this.firewallTagNamingConvention = firewallTagNamingConvention;
this.keyGenerator = keyGenerator;
}
@ -101,17 +101,16 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes,
Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
String sharedResourceName = namingConvention.create().sharedNameForGroup(group);
Template mutableTemplate = template.clone();
Template mutableTemplate = template.clone();
GoogleComputeEngineTemplateOptions templateOptions = GoogleComputeEngineTemplateOptions.class
.cast(mutableTemplate.getOptions());
assert template.getOptions().equals(templateOptions) : "options didn't clone properly";
// get or insert the network and insert a firewall with the users
// configuration
Network network = getOrCreateNetwork(templateOptions, sharedResourceName);
// Get Network
Network network = getNetwork(templateOptions.getNetworks());
// Setup Firewall rules
getOrCreateFirewalls(templateOptions, network, firewallTagNamingConvention.get(group));
templateOptions.network(network.selfLink());
templateOptions.networks(ImmutableSet.of(network.selfLink().toString()));
templateOptions.userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group);
// Configure the default credentials, if needed
@ -131,12 +130,22 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
}
/**
* Try and find a network either previously created by jclouds or user
* defined.
* Try and find a network previously created by the user.
*/
private Network getOrCreateNetwork(GoogleComputeEngineTemplateOptions templateOptions, String sharedResourceName) {
String networkName = templateOptions.network() != null ? toName(templateOptions.network()) : sharedResourceName;
return networkMap.getUnchecked(NetworkAndAddressRange.create(networkName, DEFAULT_INTERNAL_NETWORK_RANGE, null));
private Network getNetwork(Set<String> networks) {
String networkName;
if (networks == null || networks.isEmpty()){
networkName = DEFAULT_NETWORK_NAME;
}
else {
Iterator<String> iterator = networks.iterator();
networkName = nameFromNetworkString(iterator.next());
checkArgument(!iterator.hasNext(), "Error: Please specify only one network in TemplateOptions when using GCE.");
}
Network network = api.networks().get(networkName);
checkArgument(network != null, "Error: no network with name %s was found", networkName);
return network;
}
/**
@ -147,7 +156,7 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
* {@link FirewallTagNamingConvention}, with a target tag also following the
* {@link FirewallTagNamingConvention}, which opens the requested port for
* all sources on both TCP and UDP protocols.
*
*
* @see org.jclouds.googlecomputeengine.features.FirewallApi#patch(String,
* org.jclouds.googlecomputeengine.options.FirewallOptions)
*/
@ -155,32 +164,70 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
FirewallTagNamingConvention naming) {
FirewallApi firewallApi = api.firewalls();
List<AtomicReference<Operation>> operations = Lists.newArrayList();
for (Integer port : templateOptions.getInboundPorts()) {
String name = naming.name(port);
Firewall firewall = firewallApi.get(name);
if (firewall == null) {
List<String> ports = ImmutableList.of(String.valueOf(port));
List<Rule> rules = ImmutableList.of(Rule.create("tcp", ports), Rule.create("udp", ports));
FirewallOptions firewallOptions = new FirewallOptions().name(name).network(network.selfLink())
.allowedRules(rules).sourceTags(templateOptions.getTags())
.sourceRanges(of(DEFAULT_INTERNAL_NETWORK_RANGE, EXTERIOR_RANGE)).targetTags(ImmutableList.of(name));
AtomicReference<Operation> operation = Atomics.newReference(firewallApi.createInNetwork(
firewallOptions.name(), network.selfLink(), firewallOptions));
operations.add(operation);
}
int[] inboundPorts = templateOptions.getInboundPorts();
if ((inboundPorts == null) || inboundPorts.length == 0){
return;
}
for (AtomicReference<Operation> operation : operations) {
List<String> ports = simplifyPorts(inboundPorts);
String name = naming.name(ports);
Firewall firewall = firewallApi.get(name);
AtomicReference<Operation> operation = null;
if (firewall == null) {
List<Rule> rules = ImmutableList.of(Rule.create("tcp", ports), Rule.create("udp", ports));
FirewallOptions firewallOptions = new FirewallOptions().name(name).network(network.selfLink())
.allowedRules(rules).sourceTags(templateOptions.getTags())
.sourceRanges(of(DEFAULT_INTERNAL_NETWORK_RANGE, EXTERIOR_RANGE))
.targetTags(ImmutableList.of(name));
operation = Atomics.newReference(firewallApi
.createInNetwork(firewallOptions.name(), network.selfLink(), firewallOptions));
operationDone.apply(operation);
checkState(operation.get().httpErrorStatusCode() == null, "Could not insert firewall, operation failed %s",
operation);
}
}
private static String toName(URI link) {
String path = link.getPath();
return path.substring(path.lastIndexOf('/') + 1);
// Helper function for simplifying an array of ports to a list of ranges FirewallOptions expects.
public static List<String> simplifyPorts(int[] ports){
if ((ports == null) || (ports.length == 0)) {
return null;
}
ArrayList<String> output = new ArrayList<String>();
Arrays.sort(ports);
int range_start = ports[0];
int range_end = ports[0];
for (int i = 1; i < ports.length; i++) {
if ((ports[i - 1] == ports[i] - 1) || (ports[i - 1] == ports[i])){
// Range continues.
range_end = ports[i];
}
else {
// Range ends.
output.add(formatRange(range_start, range_end));
range_start = ports[i];
range_end = ports[i];
}
}
// Make sure we get the last range.
output.add(formatRange(range_start, range_end));
return output;
}
// Helper function for simplifyPorts. Formats port range strings.
private static String formatRange(int start, int finish){
if (start == finish){
return Integer.toString(start);
}
else {
return String.format("%s-%s", Integer.toString(start), Integer.toString(finish));
}
}
// Helper function for getting the network name from the full URI.
public static String nameFromNetworkString(String networkString) {
return networkString.substring(networkString.lastIndexOf('/') + 1);
}
}

View File

@ -21,6 +21,7 @@ import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.util.Properties;
import java.util.Set;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.NodeMetadata;
@ -113,4 +114,12 @@ public class GoogleComputeEngineServiceLiveTest extends BaseComputeServiceLiveTe
protected Module getSshModule() {
return new SshjSshClientModule();
}
@Override
protected void checkTagsInNodeEquals(NodeMetadata node, ImmutableSet<String> tags) {
Set<String> nodeTags = node.getTags();
for (String tag : tags){
assert nodeTags.contains(tag) : String.format("node tags did not match %s %s node:", tags, nodeTags, node);
}
}
}

View File

@ -73,39 +73,34 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
}
public void networksAndFirewallDeletedWhenAllGroupNodesAreTerminated() throws IOException, InterruptedException {
server.enqueue(instanceWithNetworkAndStatus("test-delete-networks", "test-network", RUNNING));
public void firewallDeletedWhenAllGroupNodesAreTerminated() throws IOException, InterruptedException {
server.enqueue(instanceWithNetworkAndStatus("test-delete-1", "default", RUNNING));
server.enqueue(singleRegionSingleZoneResponse());
server.enqueue(jsonResponse("/aggregated_machinetype_list.json"));
server.enqueue(jsonResponse("/operation.json"));
server.enqueue(jsonResponse("/aggregated_machinetype_list.json")); // Why are we getting machineTypes to delete an instance?
server.enqueue(jsonResponse("/operation.json")); // instance delete
server.enqueue(jsonResponse("/zone_operation.json"));
server.enqueue(instanceWithNetworkAndStatus("test-delete-networks", "test-network", TERMINATED));
server.enqueue(aggregatedListWithInstanceNetworkAndStatus("test-delete-networks", "test-network", TERMINATED));
server.enqueue(jsonResponse("/GoogleComputeEngineServiceExpectTest/network_get.json"));
server.enqueue(instanceWithNetworkAndStatus("test-delete-1", "default", TERMINATED));
server.enqueue(aggregatedListWithInstanceNetworkAndStatus("test-delete-1", "default", TERMINATED));
server.enqueue(jsonResponse("/GoogleComputeEngineServiceExpectTest/firewall_list.json"));
server.enqueue(jsonResponse("/operation.json"));
server.enqueue(jsonResponse("/zone_operation.json"));
server.enqueue(jsonResponse("/operation.json"));
server.enqueue(jsonResponse("/zone_operation.json"));
ComputeService computeService = computeService();
computeService.destroyNode(url("/jclouds/zones/us-central1-a/instances/test-delete-networks"));
computeService.destroyNode(url("/jclouds/zones/us-central1-a/instances/test-delete-1"));
assertSent(server, "GET", "/jclouds/zones/us-central1-a/instances/test-delete-networks");
assertSent(server, "GET", "/jclouds/zones/us-central1-a/instances/test-delete-1");
assertSent(server, "GET", "/projects/party/regions");
assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
assertSent(server, "DELETE", "/jclouds/zones/us-central1-a/instances/test-delete-networks");
assertSent(server, "GET", "/projects/party/aggregated/machineTypes"); // Why are we getting machineTypes to delete an instance?
assertSent(server, "DELETE", "/jclouds/zones/us-central1-a/instances/test-delete-1"); // instance delete
assertSent(server, "GET", "/projects/party/zones/us-central1-a/operations/operation-1354084865060");
assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-delete-networks");
assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-delete-1"); // get instance
assertSent(server, "GET", "/projects/party/aggregated/instances");
assertSent(server, "GET", "/projects/party/global/networks/jclouds-test-delete");
assertSent(server, "GET", "/projects/party/global/firewalls");
assertSent(server, "DELETE", "/projects/party/global/firewalls/jclouds-test-delete");
assertSent(server, "GET", "/projects/party/zones/us-central1-a/operations/operation-1354084865060");
assertSent(server, "DELETE", "/projects/party/global/networks/jclouds-test-delete");
assertSent(server, "DELETE", "/projects/party/global/firewalls/jclouds-test-delete-34sf");
assertSent(server, "GET", "/projects/party/zones/us-central1-a/operations/operation-1354084865060");
}
public void listAssignableLocations() throws Exception {
server.enqueue(singleRegionSingleZoneResponse());
@ -146,17 +141,13 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
}
public void createNodeWhenNetworkNorFirewallExistDoesNotExist() throws Exception {
public void createNodeWhenFirewallDoesNotExist() throws Exception {
server.enqueue(singleRegionSingleZoneResponse());
server.enqueue(jsonResponse("/image_list.json"));
server.enqueue(jsonResponse("/image_list_debian.json")); // per IMAGE_PROJECTS = "debian-cloud"
server.enqueue(jsonResponse("/aggregated_machinetype_list.json"));
server.enqueue(new MockResponse().setResponseCode(404)); // Network
server.enqueue(new MockResponse().setResponseCode(404)); // Network again?
server.enqueue(jsonResponse("/operation.json")); // Create Network
server.enqueue(jsonResponse("/zone_operation.json"));
server.enqueue(jsonResponse("/network_get.json"));
server.enqueue(new MockResponse().setResponseCode(404)); // Firewall
server.enqueue(jsonResponse("/network_get_default.json"));
server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall
server.enqueue(jsonResponse("/operation.json")); // Create Firewall
server.enqueue(jsonResponse("/zone_operation.json"));
server.enqueue(aggregatedListWithInstanceNetworkAndStatus("test-0", "test-network", RUNNING));
@ -179,14 +170,9 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
assertSent(server, "GET", "/projects/party/global/images");
assertSent(server, "GET", "/projects/debian-cloud/global/images");
assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
assertSent(server, "GET", "/projects/party/global/networks/jclouds-test");
assertSent(server, "GET", "/projects/party/global/networks/jclouds-test");
assertSent(server, "POST", "/projects/party/global/networks",
"{\"name\":\"jclouds-test\",\"IPv4Range\":\"10.0.0.0/8\"}");
assertSent(server, "GET", "/projects/party/zones/us-central1-a/operations/operation-1354084865060");
assertSent(server, "GET", "/projects/party/global/networks/jclouds-test");
assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-port-22");
assertSent(server, "POST", "/projects/party/global/firewalls",
assertSent(server, "GET", "/projects/party/global/networks/default");
assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall
stringFromResource("/firewall_insert_2.json"));
assertSent(server, "GET", "/projects/party/zones/us-central1-a/operations/operation-1354084865060");

View File

@ -1,130 +0,0 @@
/*
* 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.googlecomputeengine.compute.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone;
import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.features.NetworkApi;
import org.jclouds.googlecomputeengine.options.NetworkCreationOptions;
import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationTest;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
@Test
public class CreateNetworkIfNeededTest {
private static final String BASE_URL = "https://www.googleapis.com/compute/v1/projects";
public void testApply() {
GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
NetworkApi nwApi = createMock(NetworkApi.class);
Resources resources = createMock(Resources.class);
Network network = Network.create( //
"abcd", // id
new SimpleDateFormatDateService().iso8601DateParse("2014-07-18T09:47:30.826-07:00"), // creationTimestamp
URI.create(BASE_URL + "/party/global/networks/this-network"), // selfLink
"this-network", // name
null, // description
"0.0.0.0/0", // rangeIPv4
null // gatewayIPv4
);
Operation createOp = new ParseGlobalOperationTest().expected();
expect(api.networks()).andReturn(nwApi).atLeastOnce();
expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")) .andReturn(createOp);
expect(resources.operation(createOp.selfLink())).andReturn(createOp);
expect(nwApi.get("this-network")).andReturn(null);
expect(nwApi.get("this-network")).andReturn(network);
replay(api, nwApi, resources);
NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", null);
AtomicOperationDone pred = atomicOperationDone(api, resources);
CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, pred);
assertEquals(creator.apply(input), network);
verify(api, nwApi, resources);
}
public void testApplyWithGateway() {
GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
NetworkApi nwApi = createMock(NetworkApi.class);
Resources resources = createMock(Resources.class);
Network network = Network.create( //
"abcd", // id
new SimpleDateFormatDateService().iso8601DateParse("2014-07-18T09:47:30.826-07:00"), // creationTimestamp
URI.create(BASE_URL + "/party/global/networks/this-network"), // selfLink
"this-network", // name
null, // description
"0.0.0.0/0", // rangeIPv4
"1.2.3.4" // gatewayIPv4
);
Operation createOp = new ParseGlobalOperationTest().expected();
expect(api.networks()).andReturn(nwApi).atLeastOnce();
expect(nwApi.createInIPv4Range(new NetworkCreationOptions.Builder("this-network", "0.0.0.0/0")
.gatewayIPv4("1.2.3.4").build())).andReturn(createOp);
expect(resources.operation(createOp.selfLink())).andReturn(createOp);
expect(nwApi.get("this-network")).andReturn(null);
expect(nwApi.get("this-network")).andReturn(network);
replay(api, nwApi, resources);
NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", "1.2.3.4");
AtomicOperationDone pred = atomicOperationDone(api, resources);
CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, pred);
assertEquals(creator.apply(input), network);
verify(api, nwApi, resources);
}
private AtomicOperationDone atomicOperationDone(final GoogleComputeEngineApi api,
final Resources resources) {
return Guice.createInjector(new AbstractModule() { // Rather than opening ctor public
@Override protected void configure() {
bind(GoogleComputeEngineApi.class).toInstance(api);
bind(Resources.class).toInstance(resources);
}
}).getInstance(AtomicOperationDone.class);
}
}

View File

@ -1,130 +0,0 @@
/*
* 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.googlecomputeengine.compute.functions;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone;
import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.features.NetworkApi;
import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationTest;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
@Test
public class FindNetworkOrCreateTest {
private static final String BASE_URL = "https://www.googleapis.com/compute/v1/projects";
private static final Network NETWORK = Network.create( //
"abcd", // id
new SimpleDateFormatDateService().iso8601DateParse("2014-07-18T09:47:30.826-07:00"), // creationTimestamp
URI.create(BASE_URL + "/party/global/networks/this-network"), // selfLink
"this-network", // name
null, // description
"0.0.0.0/0", // rangeIPv4
null // gatewayIPv4
);
public void testLoadExisting() {
GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
NetworkApi nwApi = createMock(NetworkApi.class);
expect(api.networks()).andReturn(nwApi).atLeastOnce();
expect(nwApi.get("this-network")).andReturn(NETWORK);
replay(api, nwApi);
NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", null);
Predicate<AtomicReference<Operation>> operationDone = Predicates.alwaysFalse(); // No op should be created!
CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, operationDone);
FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator);
LoadingCache<NetworkAndAddressRange, Network> cache = CacheBuilder.newBuilder().build(loader);
assertEquals(cache.getUnchecked(input), NETWORK);
// Second call is to ensure we only need to make the API calls once.
assertEquals(cache.getUnchecked(input), NETWORK);
verify(api, nwApi);
}
public void testLoadNew() {
GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
NetworkApi nwApi = createMock(NetworkApi.class);
Resources resources = createMock(Resources.class);
Operation createOp = new ParseGlobalOperationTest().expected();
expect(api.networks()).andReturn(nwApi).atLeastOnce();
expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")).andReturn(createOp);
expect(resources.operation(createOp.selfLink())).andReturn(createOp);
// pre-creation
expect(nwApi.get("this-network")).andReturn(null).times(2);
// post-creation
expect(nwApi.get("this-network")).andReturn(NETWORK);
replay(api, nwApi, resources);
NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", null);
AtomicOperationDone pred = atomicOperationDone(resources);
CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, pred);
FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator);
LoadingCache<NetworkAndAddressRange, Network> cache = CacheBuilder.newBuilder().build(loader);
assertEquals(cache.getUnchecked(input), NETWORK);
// Second call is to ensure we only need to make the API calls once.
assertEquals(cache.getUnchecked(input), NETWORK);
verify(api, nwApi, resources);
}
private AtomicOperationDone atomicOperationDone(final Resources resources) {
return Guice.createInjector(new AbstractModule() { // Rather than opening ctor public
@Override protected void configure() {
bind(Resources.class).toInstance(resources);
}
}).getInstance(AtomicOperationDone.class);
}
}

View File

@ -45,8 +45,8 @@ public class ParseNetworkTest extends BaseGoogleComputeEngineParseTest<Network>
"13024414170909937976", // id
parse("2012-10-24T20:13:19.967"), // creationTimestamp
URI.create(baseUrl + "/party/networks/jclouds-test"), // selfLink
"default", // name
"Default network for the project", // description
"jclouds-test", // name
"A custom network for the project", // description
"10.0.0.0/8", // rangeIPv4
"10.0.0.1" // gatewayIPv4
);

View File

@ -0,0 +1,82 @@
/*
* 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.googlecomputeengine.parse;
import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.simplifyPorts;
import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.nameFromNetworkString;
import java.util.List;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import static org.testng.Assert.assertEquals;
@Test(groups = "unit", testName = "SimpleParsingTests", singleThreaded = true)
public class SimpleParsingTests {
public void testOnePort(){
int[] ports = {22};
List<String> output = simplifyPorts(ports);
assertEquals(ImmutableList.of("22"), output);
}
public void testBasic(){
int[] ports = {1, 2, 3, 4};
List<String> output = simplifyPorts(ports);
assertEquals(ImmutableList.of("1-4"), output);
}
public void testComplex(){
int[] ports = {3, 1, 5, 2, 1002, 17, 1001, 22, 80, 1000};
List<String> output = simplifyPorts(ports);
assertEquals(ImmutableList.of("1-3", "5", "17", "22", "80", "1000-1002"), output);
}
public void testEmpty(){
int[] ports = {};
List<String> output = simplifyPorts(ports);
assertEquals(null, output);
}
public void testEndSingle(){
int[] ports = {1, 2, 3, 4, 7};
List<String> output = simplifyPorts(ports);
assertEquals(ImmutableList.of("1-4", "7"), output);
}
public void testNetworkFromString(){
String network = "https://www.googleapis.com/compute/v1/projects/project/global/networks/network";
assertEquals("network", nameFromNetworkString(network));
network = "projects/project/global/networks/network";
assertEquals("network", nameFromNetworkString(network));
network = "global/networks/default";
assertEquals("default", nameFromNetworkString(network));
network = "default";
assertEquals("default", nameFromNetworkString(network));
}
}

View File

@ -4,12 +4,11 @@
"selfLink": "https://www.googleapis.com/compute/v1/projects/google/global/firewalls",
"items": [
{
"kind": "compute#firewall",
"id": "12862241031274216284",
"creationTimestamp": "2012-04-13T03:05:02.855",
"selfLink": "https://www.googleapis.com/compute/v1/projects/party/global/firewalls/jclouds-test-delete",
"name": "jclouds-test-delete",
"name": "jclouds-test-delete-34sf",
"description": "Internal traffic from default allowed",
"network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/jclouds-test-delete",
"sourceRanges": [

View File

@ -1,6 +1,6 @@
{
"name": "jclouds-test-port-22",
"network": "https://www.googleapis.com/compute/v1/projects/party/networks/jclouds-test",
"name": "jclouds-test-65f",
"network": "https://www.googleapis.com/compute/v1/projects/party/networks/default",
"sourceRanges": [
"10.0.0.0/8",
"0.0.0.0/0"
@ -9,7 +9,7 @@
"aTag"
],
"targetTags": [
"jclouds-test-port-22"
"jclouds-test-65f"
],
"allowed": [
{

View File

@ -3,7 +3,7 @@
"name": "test-1",
"networkInterfaces": [
{
"network": "https://www.googleapis.com/compute/v1/projects/party/networks/jclouds-test",
"network": "https://www.googleapis.com/compute/v1/projects/party/networks/default",
"accessConfigs": [
{
"type": "ONE_TO_ONE_NAT"
@ -25,7 +25,7 @@
"tags": {
"items": [
"aTag",
"jclouds-test-port-22"
"jclouds-test-65f"
]
},
"metadata": {

View File

@ -3,8 +3,8 @@
"id": "13024414170909937976",
"creationTimestamp": "2012-10-24T20:13:19.967",
"selfLink": "https://www.googleapis.com/compute/v1/projects/party/networks/jclouds-test",
"name": "default",
"description": "Default network for the project",
"name": "jclouds-test",
"description": "A custom network for the project",
"IPv4Range": "10.0.0.0/8",
"gatewayIPv4": "10.0.0.1"
}

View File

@ -0,0 +1,10 @@
{
"kind": "compute#network",
"id": "13024414170909937976",
"creationTimestamp": "2012-10-24T20:13:19.967",
"selfLink": "https://www.googleapis.com/compute/v1/projects/party/networks/default",
"name": "default",
"description": "Default network for the project",
"IPv4Range": "10.0.0.0/8",
"gatewayIPv4": "10.0.0.1"
}

View File

@ -9,8 +9,8 @@
"id": "13024414170909937976",
"creationTimestamp": "2012-10-24T20:13:19.967",
"selfLink": "https://www.googleapis.com/compute/v1/projects/party/networks/jclouds-test",
"name": "default",
"description": "Default network for the project",
"name": "jclouds-test",
"description": "A custom network for the project",
"IPv4Range": "10.0.0.0/8",
"gatewayIPv4": "10.0.0.1"
}