JCLOUDS-1300: Subnetwork fixes and reuse the TemplateOptions.networks

This commit is contained in:
Ignasi Barrera 2017-05-25 10:06:49 +02:00
parent 2ec28df21b
commit c83a08a8d6
39 changed files with 557 additions and 235 deletions

View File

@ -17,13 +17,11 @@
package org.jclouds.googlecomputeengine; package org.jclouds.googlecomputeengine;
import java.io.Closeable; import java.io.Closeable;
import java.net.URI;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import org.jclouds.googlecloud.config.CurrentProject; import org.jclouds.googlecloud.config.CurrentProject;
import org.jclouds.googlecomputeengine.domain.Subnetwork;
import org.jclouds.googlecomputeengine.features.AddressApi; import org.jclouds.googlecomputeengine.features.AddressApi;
import org.jclouds.googlecomputeengine.features.AggregatedListApi; import org.jclouds.googlecomputeengine.features.AggregatedListApi;
import org.jclouds.googlecomputeengine.features.BackendServiceApi; import org.jclouds.googlecomputeengine.features.BackendServiceApi;
@ -46,12 +44,10 @@ import org.jclouds.googlecomputeengine.features.SubnetworkApi;
import org.jclouds.googlecomputeengine.features.TargetHttpProxyApi; import org.jclouds.googlecomputeengine.features.TargetHttpProxyApi;
import org.jclouds.googlecomputeengine.features.TargetInstanceApi; import org.jclouds.googlecomputeengine.features.TargetInstanceApi;
import org.jclouds.googlecomputeengine.features.TargetPoolApi; import org.jclouds.googlecomputeengine.features.TargetPoolApi;
import org.jclouds.googlecomputeengine.features.TargetHttpProxyApi;
import org.jclouds.googlecomputeengine.features.UrlMapApi; import org.jclouds.googlecomputeengine.features.UrlMapApi;
import org.jclouds.googlecomputeengine.features.ZoneApi; import org.jclouds.googlecomputeengine.features.ZoneApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.Endpoint; import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.EndpointParam;
public interface GoogleComputeEngineApi extends Closeable { public interface GoogleComputeEngineApi extends Closeable {

View File

@ -22,10 +22,11 @@ import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format; import static java.lang.String.format;
import static org.jclouds.googlecloud.internal.ListPages.concat; import static org.jclouds.googlecloud.internal.ListPages.concat;
import static org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName.fromRegionAndName;
import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.nameFromNetworkString;
import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.IMAGE_PROJECTS; import static org.jclouds.googlecomputeengine.config.GoogleComputeEngineProperties.IMAGE_PROJECTS;
import java.net.URI; import java.net.URI;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -34,6 +35,7 @@ import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
@ -43,7 +45,7 @@ import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention; import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
import org.jclouds.googlecomputeengine.compute.functions.Resources; import org.jclouds.googlecomputeengine.compute.functions.Resources;
import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
import org.jclouds.googlecomputeengine.domain.AttachDisk; import org.jclouds.googlecomputeengine.domain.AttachDisk;
@ -56,6 +58,7 @@ import org.jclouds.googlecomputeengine.domain.MachineType;
import org.jclouds.googlecomputeengine.domain.NewInstance; import org.jclouds.googlecomputeengine.domain.NewInstance;
import org.jclouds.googlecomputeengine.domain.Operation; import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.domain.Region; import org.jclouds.googlecomputeengine.domain.Region;
import org.jclouds.googlecomputeengine.domain.Subnetwork;
import org.jclouds.googlecomputeengine.domain.Tags; import org.jclouds.googlecomputeengine.domain.Tags;
import org.jclouds.googlecomputeengine.domain.Zone; import org.jclouds.googlecomputeengine.domain.Zone;
import org.jclouds.googlecomputeengine.features.InstanceApi; import org.jclouds.googlecomputeengine.features.InstanceApi;
@ -95,34 +98,32 @@ public final class GoogleComputeEngineServiceAdapter
private final Predicate<AtomicReference<Operation>> operationDone; private final Predicate<AtomicReference<Operation>> operationDone;
private final Predicate<AtomicReference<Instance>> instanceVisible; private final Predicate<AtomicReference<Instance>> instanceVisible;
private final Function<Map<String, ?>, String> windowsPasswordGenerator; private final Function<Map<String, ?>, String> windowsPasswordGenerator;
private final FirewallTagNamingConvention.Factory firewallTagNamingConvention;
private final List<String> imageProjects; private final List<String> imageProjects;
private final LoadingCache<URI, Optional<Image>> diskURIToImage; private final LoadingCache<URI, Optional<Image>> diskURIToImage;
private final LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap;
@Inject GoogleComputeEngineServiceAdapter(JustProvider justProvider, GoogleComputeEngineApi api, @Inject
Predicate<AtomicReference<Operation>> operationDone, GoogleComputeEngineServiceAdapter(JustProvider justProvider, GoogleComputeEngineApi api,
Predicate<AtomicReference<Instance>> instanceVisible, Predicate<AtomicReference<Operation>> operationDone, Predicate<AtomicReference<Instance>> instanceVisible,
Function<Map<String, ?>, String> windowsPasswordGenerator, Function<Map<String, ?>, String> windowsPasswordGenerator, Resources resources,
Resources resources, @Named(IMAGE_PROJECTS) String imageProjects, LoadingCache<URI, Optional<Image>> diskURIToImage,
FirewallTagNamingConvention.Factory firewallTagNamingConvention, LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap) {
@Named(IMAGE_PROJECTS) String imageProjects,
LoadingCache<URI, Optional<Image>> diskURIToImage) {
this.justProvider = justProvider; this.justProvider = justProvider;
this.api = api; this.api = api;
this.operationDone = operationDone; this.operationDone = operationDone;
this.instanceVisible = instanceVisible; this.instanceVisible = instanceVisible;
this.windowsPasswordGenerator = windowsPasswordGenerator; this.windowsPasswordGenerator = windowsPasswordGenerator;
this.resources = resources; this.resources = resources;
this.firewallTagNamingConvention = firewallTagNamingConvention;
this.imageProjects = Splitter.on(',').omitEmptyStrings().splitToList(imageProjects); this.imageProjects = Splitter.on(',').omitEmptyStrings().splitToList(imageProjects);
this.diskURIToImage = diskURIToImage; this.diskURIToImage = diskURIToImage;
this.subnetworksMap = subnetworksMap;
} }
@Override public NodeAndInitialCredentials<Instance> createNodeWithGroupEncodedIntoName(String group, String name, @Override public NodeAndInitialCredentials<Instance> createNodeWithGroupEncodedIntoName(String group, String name,
Template template) { Template template) {
GoogleComputeEngineTemplateOptions options = GoogleComputeEngineTemplateOptions.class.cast(template.getOptions()); GoogleComputeEngineTemplateOptions options = GoogleComputeEngineTemplateOptions.class.cast(template.getOptions());
checkNotNull(options.getNetworks(), "template options must specify a network"); checkNotNull(options.getNetworks(), "template options must specify a network or subnetwork");
checkNotNull(template.getHardware().getUri(), "hardware must have a URI"); checkNotNull(template.getHardware().getUri(), "hardware must have a URI");
checkNotNull(template.getImage().getUri(), "image URI is null"); checkNotNull(template.getImage().getUri(), "image URI is null");
@ -131,15 +132,19 @@ public final class GoogleComputeEngineServiceAdapter
List<AttachDisk> disks = Lists.newArrayList(); List<AttachDisk> disks = Lists.newArrayList();
disks.add(AttachDisk.newBootDisk(template.getImage().getUri(), getDiskTypeArgument(options, zone))); disks.add(AttachDisk.newBootDisk(template.getImage().getUri(), getDiskTypeArgument(options, zone)));
Iterator<String> networks = options.getNetworks().iterator(); URI network = URI.create(options.getNetworks().iterator().next());
URI subnetwork = null;
URI network = URI.create(networks.next());
assert !networks.hasNext() : "Error: Options should specify only one network"; if (isSubnetwork(network)) {
String region = template.getLocation().getParent().getId();
Iterator<String> subnetworks = options.getSubnetworks().iterator(); RegionAndName subnetRef = fromRegionAndName(region, nameFromNetworkString(network.toString()));
// This must be present, since the subnet is validated and its URI
URI subnetwork = subnetworks.hasNext() ? URI.create(subnetworks.next()) : null; // obtained in the CreateNodesWithGroupEncodedIntoNameThenAddToSet
assert !subnetworks.hasNext() : "Error: Options should specify only one subnetwork"; // strategy
Optional<Subnetwork> subnet = subnetworksMap.getUnchecked(subnetRef);
network = subnet.get().network();
subnetwork = subnet.get().selfLink();
}
Scheduling scheduling = getScheduling(options); Scheduling scheduling = getScheduling(options);
@ -342,4 +347,8 @@ public final class GoogleComputeEngineServiceAdapter
return Scheduling.create(onHostMaintenance, automaticRestart, options.preemptible()); return Scheduling.create(onHostMaintenance, automaticRestart, options.preemptible());
} }
private static boolean isSubnetwork(URI uri) {
return uri.toString().contains("/subnetworks/");
}
} }

View File

@ -55,6 +55,7 @@ import org.jclouds.googlecomputeengine.compute.functions.OrphanedGroupsFromDeadN
import org.jclouds.googlecomputeengine.compute.functions.Resources; import org.jclouds.googlecomputeengine.compute.functions.Resources;
import org.jclouds.googlecomputeengine.compute.functions.ResetWindowsPassword; import org.jclouds.googlecomputeengine.compute.functions.ResetWindowsPassword;
import org.jclouds.googlecomputeengine.compute.loaders.DiskURIToImage; import org.jclouds.googlecomputeengine.compute.loaders.DiskURIToImage;
import org.jclouds.googlecomputeengine.compute.loaders.SubnetworkLoader;
import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
import org.jclouds.googlecomputeengine.compute.predicates.AtomicInstanceVisible; import org.jclouds.googlecomputeengine.compute.predicates.AtomicInstanceVisible;
import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone; import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone;
@ -64,6 +65,7 @@ import org.jclouds.googlecomputeengine.domain.Image;
import org.jclouds.googlecomputeengine.domain.Instance; import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.MachineType; import org.jclouds.googlecomputeengine.domain.MachineType;
import org.jclouds.googlecomputeengine.domain.Operation; import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.domain.Subnetwork;
import org.jclouds.location.suppliers.ImplicitLocationSupplier; import org.jclouds.location.suppliers.ImplicitLocationSupplier;
import org.jclouds.location.suppliers.implicit.FirstZone; import org.jclouds.location.suppliers.implicit.FirstZone;
@ -84,6 +86,7 @@ import org.jclouds.compute.domain.internal.TemplateBuilderImpl;
import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement; import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatementWithoutPublicKey; import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatementWithoutPublicKey;
import org.jclouds.googlecomputeengine.compute.domain.internal.GoogleComputeEngineArbitraryCpuRamTemplateBuilderImpl; import org.jclouds.googlecomputeengine.compute.domain.internal.GoogleComputeEngineArbitraryCpuRamTemplateBuilderImpl;
import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
public final class GoogleComputeEngineServiceContextModule public final class GoogleComputeEngineServiceContextModule
extends ComputeServiceAdapterContextModule<Instance, MachineType, Image, Location> { extends ComputeServiceAdapterContextModule<Instance, MachineType, Image, Location> {
@ -137,6 +140,9 @@ public final class GoogleComputeEngineServiceContextModule
bind(new TypeLiteral<CacheLoader<URI, Optional<Image>>>() { bind(new TypeLiteral<CacheLoader<URI, Optional<Image>>>() {
}).to(DiskURIToImage.class); }).to(DiskURIToImage.class);
bind(new TypeLiteral<CacheLoader<RegionAndName, Optional<Subnetwork>>>() {
}).to(SubnetworkLoader.class);
bindHttpApi(binder(), Resources.class); bindHttpApi(binder(), Resources.class);
} }
@ -203,8 +209,14 @@ public final class GoogleComputeEngineServiceContextModule
@Provides @Provides
@Singleton @Singleton
protected LoadingCache<URI, Optional<Image>> diskURIToImageMap( protected LoadingCache<URI, Optional<Image>> diskURIToImageMap(CacheLoader<URI, Optional<Image>> in) {
CacheLoader<URI, Optional<Image>> in) { return CacheBuilder.newBuilder().build(in);
}
@Provides
@Singleton
protected LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap(
CacheLoader<RegionAndName, Optional<Subnetwork>> in) {
return CacheBuilder.newBuilder().build(in); return CacheBuilder.newBuilder().build(in);
} }

View File

@ -0,0 +1,53 @@
/*
* 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.internal;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.auto.value.AutoValue;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
/**
* Helpful when looking for resources by region and name
*/
@AutoValue
public abstract class RegionAndName {
public abstract String regionId();
public abstract String name();
RegionAndName() {
}
public static RegionAndName fromSlashEncoded(String name) {
Iterable<String> parts = Splitter.on('/').split(checkNotNull(name, "name"));
checkArgument(Iterables.size(parts) == 2, "name must be in format regionId/name");
return fromRegionAndName(Iterables.get(parts, 0), Iterables.get(parts, 1));
}
public static RegionAndName fromRegionAndName(String regionId, String name) {
return new AutoValue_RegionAndName(regionId, name);
}
public String slashEncode() {
return regionId() + "/" + name();
}
}

View File

@ -16,42 +16,38 @@
*/ */
package org.jclouds.googlecomputeengine.compute.loaders; package org.jclouds.googlecomputeengine.compute.loaders;
import java.net.URI;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.googlecomputeengine.compute.functions.Resources; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
import org.jclouds.googlecomputeengine.domain.Subnetwork; import org.jclouds.googlecomputeengine.domain.Subnetwork;
import org.jclouds.logging.Logger;
import com.google.common.base.Optional;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
@Singleton @Singleton
public class SubnetworkLoader extends CacheLoader<URI, Subnetwork> { public class SubnetworkLoader extends CacheLoader<RegionAndName, Optional<Subnetwork>> {
@Resource
protected Logger logger = Logger.NULL;
private final Resources resources; private final GoogleComputeEngineApi api;
@Inject @Inject
SubnetworkLoader(Resources resources) { SubnetworkLoader(GoogleComputeEngineApi api) {
this.resources = resources; this.api = api;
} }
@Override @Override
public Subnetwork load(URI key) throws ExecutionException { public Optional<Subnetwork> load(RegionAndName key) throws ExecutionException {
try { try {
return resources.subnetwork(key); return Optional.fromNullable(api.subnetworksInRegion(key.regionId()).get(key.name()));
} catch (Exception e) { } catch (Exception ex) {
throw new ExecutionException(message(key, e), e); throw new ExecutionException(message(key, ex), ex);
} }
} }
public static String message(URI key, Exception e) { public static String message(RegionAndName key, Exception ex) {
return String.format("could not find image for disk %s: %s", key.toString(), e.getMessage()); return String.format("could not find subnet %s in region %s: %s", key.name(), key.regionId(), ex.getMessage());
} }
} }

View File

@ -18,14 +18,12 @@ package org.jclouds.googlecomputeengine.compute.options;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount; import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import com.google.common.collect.ImmutableSet;
/** Instance options specific to Google Compute Engine. */ /** Instance options specific to Google Compute Engine. */
public final class GoogleComputeEngineTemplateOptions extends TemplateOptions { public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
@ -35,7 +33,6 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
private List<ServiceAccount> serviceAccounts; private List<ServiceAccount> serviceAccounts;
private String bootDiskType; private String bootDiskType;
private boolean preemptible = false; private boolean preemptible = false;
private Set<String> subnetworks;
@Override @Override
public GoogleComputeEngineTemplateOptions clone() { public GoogleComputeEngineTemplateOptions clone() {
@ -138,11 +135,6 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
return serviceAccounts; return serviceAccounts;
} }
public Set<String> getSubnetworks() {
return subnetworks;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -295,22 +287,6 @@ public final class GoogleComputeEngineTemplateOptions extends TemplateOptions {
return GoogleComputeEngineTemplateOptions.class.cast(super.networks(networks)); return GoogleComputeEngineTemplateOptions.class.cast(super.networks(networks));
} }
/**
* Assigns subnetworks to the machine.
*/
public GoogleComputeEngineTemplateOptions subnetworks(Iterable<String> networks) {
this.subnetworks = ImmutableSet.copyOf(networks);
return this;
}
/**
* Assigns subnetworks to the machine.
*/
public GoogleComputeEngineTemplateOptions subnetworks(String... networks) {
this.subnetworks = ImmutableSet.copyOf(networks);
return this;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */

View File

@ -19,6 +19,8 @@ package org.jclouds.googlecomputeengine.compute.strategy;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.of; import static com.google.common.collect.ImmutableList.of;
import static org.jclouds.domain.LocationScope.ZONE;
import static org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName.fromRegionAndName;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -41,20 +43,26 @@ import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.domain.Location;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.compute.domain.internal.RegionAndName;
import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention; import org.jclouds.googlecomputeengine.compute.functions.FirewallTagNamingConvention;
import org.jclouds.googlecomputeengine.compute.functions.Resources;
import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
import org.jclouds.googlecomputeengine.domain.Firewall; import org.jclouds.googlecomputeengine.domain.Firewall;
import org.jclouds.googlecomputeengine.domain.Firewall.Rule; import org.jclouds.googlecomputeengine.domain.Firewall.Rule;
import org.jclouds.googlecomputeengine.domain.Network; import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Operation; import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.domain.Subnetwork;
import org.jclouds.googlecomputeengine.features.FirewallApi; import org.jclouds.googlecomputeengine.features.FirewallApi;
import org.jclouds.googlecomputeengine.options.FirewallOptions; import org.jclouds.googlecomputeengine.options.FirewallOptions;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.ssh.SshKeyPairGenerator; import org.jclouds.ssh.SshKeyPairGenerator;
import com.google.common.base.Optional;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
@ -72,9 +80,11 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
public static final String DEFAULT_NETWORK_NAME = "default"; public static final String DEFAULT_NETWORK_NAME = "default";
private final GoogleComputeEngineApi api; private final GoogleComputeEngineApi api;
private final Resources resources;
private final Predicate<AtomicReference<Operation>> operationDone; private final Predicate<AtomicReference<Operation>> operationDone;
private final FirewallTagNamingConvention.Factory firewallTagNamingConvention; private final FirewallTagNamingConvention.Factory firewallTagNamingConvention;
private final SshKeyPairGenerator keyGenerator; private final SshKeyPairGenerator keyGenerator;
private final LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap;
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
@ -87,14 +97,17 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
GroupNamingConvention.Factory namingConvention, GroupNamingConvention.Factory namingConvention,
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
GoogleComputeEngineApi api, Predicate<AtomicReference<Operation>> operationDone, GoogleComputeEngineApi api, Resources resources, Predicate<AtomicReference<Operation>> operationDone,
FirewallTagNamingConvention.Factory firewallTagNamingConvention, SshKeyPairGenerator keyGenerator) { FirewallTagNamingConvention.Factory firewallTagNamingConvention, SshKeyPairGenerator keyGenerator,
LoadingCache<RegionAndName, Optional<Subnetwork>> subnetworksMap) {
super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
this.api = api; this.api = api;
this.resources = resources;
this.operationDone = operationDone; this.operationDone = operationDone;
this.firewallTagNamingConvention = firewallTagNamingConvention; this.firewallTagNamingConvention = firewallTagNamingConvention;
this.keyGenerator = keyGenerator; this.keyGenerator = keyGenerator;
this.subnetworksMap = subnetworksMap;
} }
@Override @Override
@ -102,16 +115,13 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes, Set<NodeMetadata> goodNodes, Map<NodeMetadata, Exception> badNodes,
Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
Template mutableTemplate = template.clone();
GoogleComputeEngineTemplateOptions templateOptions = GoogleComputeEngineTemplateOptions.class GoogleComputeEngineTemplateOptions templateOptions = GoogleComputeEngineTemplateOptions.class
.cast(mutableTemplate.getOptions()); .cast(template.getOptions());
assert template.getOptions().equals(templateOptions) : "options didn't clone properly"; assert template.getOptions().equals(templateOptions) : "options didn't clone properly";
// Get Network // Configure networking
Network network = getNetwork(templateOptions.getNetworks()); configureNetworking(group, templateOptions, template.getLocation());
// Setup Firewall rules
getOrCreateFirewalls(templateOptions, network, firewallTagNamingConvention.get(group));
templateOptions.networks(ImmutableSet.of(network.selfLink().toString()));
templateOptions.userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group); templateOptions.userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group);
// Configure the default credentials, if needed // Configure the default credentials, if needed
@ -123,30 +133,48 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
} }
if (templateOptions.getRunScript() != null && templateOptions.getLoginPrivateKey() == null) { if (templateOptions.getRunScript() != null && templateOptions.getLoginPrivateKey() == null) {
logger.warn(">> A runScript has been configured but no SSH key has been provided." logger.warn(">> a runScript has been configured but no SSH key has been provided."
+ " Authentication will delegate to the ssh-agent"); + " Authentication will delegate to the ssh-agent");
} }
return super.execute(group, count, mutableTemplate, goodNodes, badNodes, customizationResponses); return super.execute(group, count, template, goodNodes, badNodes, customizationResponses);
} }
/** /**
* Try and find a network previously created by the user. * Configure the networks taking into account that users may have configured
* a custom subnet or a legacy network.
*/ */
private Network getNetwork(Set<String> networks) { private void configureNetworking(String group, GoogleComputeEngineTemplateOptions options, Location location) {
String networkName; String networkName = null;
if (networks == null || networks.isEmpty()){ Network network = null;
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.");
if (options.getNetworks().isEmpty()) {
networkName = DEFAULT_NETWORK_NAME;
} else {
Iterator<String> iterator = options.getNetworks().iterator();
networkName = nameFromNetworkString(iterator.next());
checkArgument(!iterator.hasNext(),
"Error: Please specify only one network/subnetwork in TemplateOptions when using GCE.");
} }
Network network = api.networks().get(networkName);
String region = ZONE == location.getScope() ? location.getParent().getId() : location.getId();
Optional<Subnetwork> subnet = subnetworksMap.getUnchecked(fromRegionAndName(region, networkName));
if (subnet.isPresent()) {
network = resources.network(subnet.get().network());
options.networks(ImmutableSet.of(subnet.get().selfLink().toString()));
logger.debug(">> attaching nodes to subnet(%s) in region(%s)", subnet.get().name(), region);
} else {
logger.warn(">> subnet(%s) was not found in region(%s). Trying to find a matching legacy network...",
networkName, region);
network = api.networks().get(networkName);
options.networks(ImmutableSet.of(network.selfLink().toString()));
logger.debug(">> attaching nodes to legacy network(%s)", network.name());
}
checkArgument(network != null, "Error: no network with name %s was found", networkName); checkArgument(network != null, "Error: no network with name %s was found", networkName);
return network;
// Setup Firewall rules
getOrCreateFirewalls(options, network, subnet, firewallTagNamingConvention.get(group));
} }
/** /**
@ -162,7 +190,7 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
* org.jclouds.googlecomputeengine.options.FirewallOptions) * org.jclouds.googlecomputeengine.options.FirewallOptions)
*/ */
private void getOrCreateFirewalls(GoogleComputeEngineTemplateOptions templateOptions, Network network, private void getOrCreateFirewalls(GoogleComputeEngineTemplateOptions templateOptions, Network network,
FirewallTagNamingConvention naming) { Optional<Subnetwork> subnet, FirewallTagNamingConvention naming) {
Set<String> tags = Sets.newLinkedHashSet(templateOptions.getTags()); Set<String> tags = Sets.newLinkedHashSet(templateOptions.getTags());
@ -188,11 +216,14 @@ public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
String name = naming.name(ports); String name = naming.name(ports);
Firewall firewall = firewallApi.get(name); Firewall firewall = firewallApi.get(name);
AtomicReference<Operation> operation = null; AtomicReference<Operation> operation = null;
String interiorRange = subnet.isPresent() ? subnet.get().ipCidrRange() : DEFAULT_INTERNAL_NETWORK_RANGE;
if (firewall == null) { if (firewall == null) {
List<Rule> rules = ImmutableList.of(Rule.create("tcp", ports), Rule.create("udp", ports)); List<Rule> rules = ImmutableList.of(Rule.create("tcp", ports), Rule.create("udp", ports));
FirewallOptions firewallOptions = new FirewallOptions().name(name).network(network.selfLink()) FirewallOptions firewallOptions = new FirewallOptions().name(name).network(network.selfLink())
.allowedRules(rules).sourceTags(templateOptions.getTags()) .allowedRules(rules).sourceTags(templateOptions.getTags())
.sourceRanges(of(DEFAULT_INTERNAL_NETWORK_RANGE, EXTERIOR_RANGE)) .sourceRanges(of(interiorRange, EXTERIOR_RANGE))
.targetTags(ImmutableList.of(name)); .targetTags(ImmutableList.of(name));
operation = Atomics.newReference(firewallApi operation = Atomics.newReference(firewallApi

View File

@ -126,13 +126,11 @@ public final class GoogleComputeEngineHttpApiModule extends HttpApiModule<Google
private final GetProject api; private final GetProject api;
private final Supplier<URI> defaultEndpoint; private final Supplier<URI> defaultEndpoint;
private final String identityName;
@Inject @Inject
UseApiToResolveProjectName(GetProject api, @Provider Supplier<URI> defaultEndpoint, ProviderMetadata metadata) { UseApiToResolveProjectName(GetProject api, @Provider Supplier<URI> defaultEndpoint, ProviderMetadata metadata) {
this.api = api; this.api = api;
this.defaultEndpoint = defaultEndpoint; this.defaultEndpoint = defaultEndpoint;
this.identityName = metadata.getApiMetadata().getIdentityName();
} }
@Override public URI apply(Credentials in) { @Override public URI apply(Credentials in) {

View File

@ -25,6 +25,7 @@ import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
/** /**
* Represents a network used to enable instance communication. * Represents a network used to enable instance communication.
@ -46,8 +47,6 @@ public abstract class Network {
public abstract String name(); public abstract String name();
public abstract NetworkType type();
@Nullable public abstract String description(); @Nullable public abstract String description();
/** /**
@ -61,26 +60,24 @@ public abstract class Network {
* If not specified, the default value is the first usable address in IPv4Range. * If not specified, the default value is the first usable address in IPv4Range.
*/ */
@Nullable public abstract String gatewayIPv4(); @Nullable public abstract String gatewayIPv4();
public abstract boolean autoCreateSubnetworks();
@Nullable public abstract List<URI> subnetworks(); public abstract List<URI> subnetworks();
public static Network create(String id, Date creationTimestamp, URI selfLink, String name, String description, String rangeIPv4, @SerializedNames({ "id", "creationTimestamp", "selfLink", "name", "description", "IPv4Range", "gatewayIPv4",
String gatewayIPv4) { "autoCreateSubnetworks", "subnetworks" })
return new AutoValue_Network(id, creationTimestamp, selfLink, name, NetworkType.LegacyNetwork, description, public static Network create(String id, Date creationTimestamp, URI selfLink, String name, String description,
rangeIPv4, gatewayIPv4, null); String rangeIPv4, String gatewayIPv4, boolean autoCreateSubnetworks, List<URI> subnetworks) {
} return new AutoValue_Network(id, creationTimestamp, selfLink, name, description, rangeIPv4, gatewayIPv4,
autoCreateSubnetworks, subnetworks == null ? ImmutableList.<URI> of() : ImmutableList.copyOf(subnetworks));
@SerializedNames({ "id", "creationTimestamp", "selfLink", "name", "description", "IPv4Range", "gatewayIPv4", "autoCreateSubnetworks", "subnetworks" })
public static Network create(String id, Date creationTimestamp, URI selfLink, String name, String description, String rangeIPv4,
String gatewayIPv4, String autoCreateSubnetworks, List<URI> subnetworks) {
NetworkType type;
type = !Strings.isNullOrEmpty(rangeIPv4) ? NetworkType.LegacyNetwork
: (autoCreateSubnetworks.equals("true") ? NetworkType.AutoSubnetwork
: NetworkType.CustomNetwork);
return new AutoValue_Network(id, creationTimestamp, selfLink, name, type, description, rangeIPv4, gatewayIPv4,
subnetworks);
} }
Network() { Network() {
} }
public NetworkType type() {
return !Strings.isNullOrEmpty(rangeIPv4()) ? NetworkType.LegacyNetwork
: (autoCreateSubnetworks() ? NetworkType.AutoSubnetwork : NetworkType.CustomNetwork);
}
} }

View File

@ -43,20 +43,11 @@ public abstract class NewInstance {
abstract List<AccessConfig> accessConfigs(); abstract List<AccessConfig> accessConfigs();
static NetworkInterface create(URI network) {
return create(network, Arrays.asList(AccessConfig.create(null, Type.ONE_TO_ONE_NAT, null)));
}
static NetworkInterface create(URI network, URI subnetwork) { static NetworkInterface create(URI network, URI subnetwork) {
return create(network, subnetwork, return create(network, subnetwork,
Arrays.asList(AccessConfig.create(null, Type.ONE_TO_ONE_NAT, null))); Arrays.asList(AccessConfig.create(null, Type.ONE_TO_ONE_NAT, null)));
} }
@SerializedNames({ "network", "accessConfigs" })
static NetworkInterface create(URI network, List<AccessConfig> accessConfigs) {
return new AutoValue_NewInstance_NetworkInterface(network, null, accessConfigs);
}
@SerializedNames({ "network", "subnetwork", "accessConfigs" }) @SerializedNames({ "network", "subnetwork", "accessConfigs" })
static NetworkInterface create(URI network, URI subnetwork, List<AccessConfig> accessConfigs) { static NetworkInterface create(URI network, URI subnetwork, List<AccessConfig> accessConfigs) {
return new AutoValue_NewInstance_NetworkInterface(network, subnetwork, accessConfigs); return new AutoValue_NewInstance_NetworkInterface(network, subnetwork, accessConfigs);
@ -88,20 +79,11 @@ public abstract class NewInstance {
@Nullable public abstract Scheduling scheduling(); @Nullable public abstract Scheduling scheduling();
/** Convenience for creating a new instance with only a boot disk and minimal parameters. */ /** Convenience for creating a new instance with only a boot disk and minimal parameters. */
public static NewInstance create(String name, URI machineType, URI network, URI sourceImage) {
return create(name, machineType, network, Arrays.asList(AttachDisk.newBootDisk(sourceImage)), null, null);
}
public static NewInstance create(String name, URI machineType, URI network, URI subnetwork, URI sourceImage) { public static NewInstance create(String name, URI machineType, URI network, URI subnetwork, URI sourceImage) {
return create(name, machineType, network, subnetwork, Arrays.asList(AttachDisk.newBootDisk(sourceImage)), null, return create(name, machineType, network, subnetwork, Arrays.asList(AttachDisk.newBootDisk(sourceImage)), null,
null); null);
} }
public static NewInstance create(String name, URI machineType, URI network, List<AttachDisk> disks,
@Nullable String description, @Nullable Tags tags) {
return create(name, machineType, network, null, disks, description, tags);
}
public static NewInstance create(String name, URI machineType, URI network, @Nullable URI subnetwork, public static NewInstance create(String name, URI machineType, URI network, @Nullable URI subnetwork,
List<AttachDisk> disks, @Nullable String description, @Nullable Tags tags) { List<AttachDisk> disks, @Nullable String description, @Nullable Tags tags) {
checkArgument(disks.get(0).boot(), "disk 0 must be a boot disk! %s", disks); checkArgument(disks.get(0).boot(), "disk 0 must be a boot disk! %s", disks);
@ -112,8 +94,9 @@ public abstract class NewInstance {
foundBoot = true; foundBoot = true;
} }
} }
return create(name, machineType, null, ImmutableList.of(NetworkInterface.create(network)), ImmutableList.copyOf(disks), return create(name, machineType, null, ImmutableList.of(NetworkInterface.create(network, subnetwork)),
description, tags != null ? tags : Tags.create(), Metadata.create(), null, null); ImmutableList.copyOf(disks), description, tags != null ? tags : Tags.create(), Metadata.create(), null,
null);
} }
@SerializedNames({ "name", "machineType", "canIpForward", "networkInterfaces", "disks", "description", @SerializedNames({ "name", "machineType", "canIpForward", "networkInterfaces", "disks", "description",
@ -140,14 +123,6 @@ public abstract class NewInstance {
private List<ServiceAccount> serviceAccounts; private List<ServiceAccount> serviceAccounts;
private Scheduling scheduling; private Scheduling scheduling;
public Builder(String name, URI machineType, URI network, List<AttachDisk> disks) {
checkNotNull(name, "NewInstance name cannot be null");
this.name = name;
this.machineType = machineType;
this.networkInterfaces = ImmutableList.of(NetworkInterface.create(network));
this.disks = disks;
}
public Builder(String name, URI machineType, URI network, URI subnetwork, List<AttachDisk> disks) { public Builder(String name, URI machineType, URI network, URI subnetwork, List<AttachDisk> disks) {
checkNotNull(name, "NewInstance name cannot be null"); checkNotNull(name, "NewInstance name cannot be null");
this.name = name; this.name = name;
@ -156,14 +131,6 @@ public abstract class NewInstance {
this.disks = disks; this.disks = disks;
} }
public Builder(String name, URI machineType, URI network, URI sourceImage) {
checkNotNull(name, "NewInstance name cannot be null");
this.name = name;
this.machineType = machineType;
this.networkInterfaces = ImmutableList.of(NetworkInterface.create(network));
this.disks = Arrays.asList(AttachDisk.newBootDisk(sourceImage));
}
public Builder(String name, URI machineType, URI network, URI subnetwork, URI sourceImage) { public Builder(String name, URI machineType, URI network, URI subnetwork, URI sourceImage) {
checkNotNull(name, "NewInstance name cannot be null"); checkNotNull(name, "NewInstance name cannot be null");
this.name = name; this.name = name;

View File

@ -48,13 +48,12 @@ public abstract class Subnetwork {
public abstract URI region(); public abstract URI region();
@SerializedNames({ "id", "creationTimestamp", "selfLink", "name", @SerializedNames({ "id", "creationTimestamp", "selfLink", "name", "description", "gatewayAddress", "network",
"description", "gatewayAddress", "network", "ipCidrRange", "region" }) "ipCidrRange", "region" })
public static Subnetwork create(String id, Date creationTimestamp, URI selfLink, String name, public static Subnetwork create(String id, Date creationTimestamp, URI selfLink, String name, String description,
String description, String gatewayAddress, URI network, String gatewayAddress, URI network, String ipCidrRange, URI region) {
String ipCidrRange, URI region) { return new AutoValue_Subnetwork(id, creationTimestamp, selfLink, name, description, gatewayAddress, network,
return new AutoValue_Subnetwork(id, creationTimestamp, selfLink, name, description, ipCidrRange, region);
gatewayAddress, network, ipCidrRange, region);
} }
Subnetwork() { Subnetwork() {

View File

@ -43,7 +43,7 @@ import org.jclouds.javax.annotation.Nullable;
import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.oauth.v2.filters.OAuthFilter;
import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.MapBinder; import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding; import org.jclouds.rest.annotations.SkipEncoding;
@ -66,7 +66,7 @@ public interface NetworkApi {
Network get(@PathParam("network") String networkName); Network get(@PathParam("network") String networkName);
/** /**
* Creates a persistent network resource in the specified project with the specified range. * Creates a legacy persistent network resource in the specified project with the specified range.
* *
* @param networkName the network name * @param networkName the network name
* @param IPv4Range the range of the network to be inserted. * @param IPv4Range the range of the network to be inserted.
@ -76,21 +76,33 @@ public interface NetworkApi {
@Named("Networks:insert") @Named("Networks:insert")
@POST @POST
@Produces(APPLICATION_JSON) @Produces(APPLICATION_JSON)
@MapBinder(BindToJsonPayload.class) @Payload("%7B\"name\":\"{name}\",\"IPv4Range\":\"{IPv4Range}\"%7D")
Operation createInIPv4Range(@PayloadParam("name") String networkName, Operation createLegacy(@PayloadParam("name") String networkName, @PayloadParam("IPv4Range") String IPv4Range);
@PayloadParam("IPv4Range") String IPv4Range);
/** /**
* Creates a persistent network resource in the specified project with the specified range and specified gateway. * Creates a custom persistent network resource in the specified project with the specified range.
* *
* @param options the options to create the network. * @param networkName the network name
* @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to
* you, and look for the status field. * you, and look for the status field.
*/ */
@Named("Networks:insert") @Named("Networks:insert")
@POST @POST
@Produces(APPLICATION_JSON) @Produces(APPLICATION_JSON)
Operation createInIPv4Range(@BinderParam(BindToJsonPayload.class) NetworkCreationOptions options); @Payload("%7B\"autoCreateSubnetworks\":false,\"name\":\"{name}\"%7D")
Operation createCustom(@PayloadParam("name") String networkName);
/**
* Creates a persistent network resource in the specified project with the specified options.
*
* @param options the network options.
* @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to
* you, and look for the status field.
*/
@Named("Networks:insert")
@POST
@Produces(APPLICATION_JSON)
Operation create(@BinderParam(BindToJsonPayload.class) NetworkCreationOptions options);
/** Deletes a network by name and returns the operation in progress, or null if not found. */ /** Deletes a network by name and returns the operation in progress, or null if not found. */
@Named("Networks:delete") @Named("Networks:delete")
@ -124,7 +136,7 @@ public interface NetworkApi {
@Transform(NetworkPages.class) @Transform(NetworkPages.class)
Iterator<ListPage<Network>> list(ListOptions options); Iterator<ListPage<Network>> list(ListOptions options);
final class NetworkPages extends BaseToIteratorOfListPage<Network, NetworkPages> { static final class NetworkPages extends BaseToIteratorOfListPage<Network, NetworkPages> {
private final GoogleComputeEngineApi api; private final GoogleComputeEngineApi api;

View File

@ -18,7 +18,6 @@ package org.jclouds.googlecomputeengine.features;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import java.net.URI;
import java.util.Iterator; import java.util.Iterator;
import javax.inject.Inject; import javax.inject.Inject;
@ -43,11 +42,7 @@ import org.jclouds.googlecomputeengine.options.SubnetworkCreationOptions;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.oauth.v2.filters.OAuthFilter; import org.jclouds.oauth.v2.filters.OAuthFilter;
import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding; import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.Transform; import org.jclouds.rest.annotations.Transform;
@ -107,6 +102,12 @@ public interface SubnetworkApi {
@GET @GET
@Transform(SubnetworkPages.class) @Transform(SubnetworkPages.class)
Iterator<ListPage<Subnetwork>> list(); Iterator<ListPage<Subnetwork>> list();
/** @see #listPage(String, ListOptions) */
@Named("Subnetworks:list")
@GET
@Transform(SubnetworkPages.class)
Iterator<ListPage<Subnetwork>> list(ListOptions options);
static final class SubnetworkPages extends BaseCallerArg0ToIteratorOfListPage<Subnetwork, SubnetworkPages> { static final class SubnetworkPages extends BaseCallerArg0ToIteratorOfListPage<Subnetwork, SubnetworkPages> {

View File

@ -37,18 +37,20 @@ public abstract class NetworkCreationOptions {
* The range of internal addresses that are legal on this network. This range is a CIDR * The range of internal addresses that are legal on this network. This range is a CIDR
* specification, for example: {@code 192.168.0.0/16}. * specification, for example: {@code 192.168.0.0/16}.
*/ */
public abstract String rangeIPv4(); @Nullable public abstract String rangeIPv4();
/** /**
* This must be within the range specified by IPv4Range, and is typically the first usable address in that range. * This must be within the range specified by IPv4Range, and is typically the first usable address in that range.
* If not specified, the default value is the first usable address in IPv4Range. * If not specified, the default value is the first usable address in IPv4Range.
*/ */
@Nullable public abstract String gatewayIPv4(); @Nullable public abstract String gatewayIPv4();
@Nullable public abstract Boolean autoCreateSubnetworks();
@SerializedNames({ "name", "description", "IPv4Range", "gatewayIPv4" }) @SerializedNames({ "name", "description", "IPv4Range", "gatewayIPv4", "autoCreateSubnetworks" })
public static NetworkCreationOptions create(String name, String description, String rangeIPv4, public static NetworkCreationOptions create(String name, String description, String rangeIPv4,
String gatewayIPv4) { String gatewayIPv4, Boolean autoCreateSubnetworks) {
return new AutoValue_NetworkCreationOptions(name, description, rangeIPv4, gatewayIPv4); return new AutoValue_NetworkCreationOptions(name, description, rangeIPv4, gatewayIPv4, autoCreateSubnetworks);
} }
NetworkCreationOptions() { NetworkCreationOptions() {
@ -59,10 +61,15 @@ public abstract class NetworkCreationOptions {
private String description; private String description;
private String rangeIPv4; private String rangeIPv4;
private String gatewayIPv4; private String gatewayIPv4;
private Boolean autoCreateSubnetworks;
public Builder(String name, String rangeIPv4){
public Builder(String name) {
this.name = name; this.name = name;
}
public Builder rangeIPv4(String rangeIPv4) {
this.rangeIPv4 = rangeIPv4; this.rangeIPv4 = rangeIPv4;
return this;
} }
public Builder description(String description) { public Builder description(String description) {
@ -74,11 +81,15 @@ public abstract class NetworkCreationOptions {
this.gatewayIPv4 = gatewayIPv4; this.gatewayIPv4 = gatewayIPv4;
return this; return this;
} }
public Builder autoCreateSubnetworks(Boolean autoCreateSubnetworks) {
this.autoCreateSubnetworks = autoCreateSubnetworks;
return this;
}
public NetworkCreationOptions build() { public NetworkCreationOptions build() {
checkNotNull(name, "NetworkCreationOptions name cannot be null"); checkNotNull(name, "NetworkCreationOptions name cannot be null");
checkNotNull(rangeIPv4, "NetworkCreationOptions rangeIPv4 cannot be null"); return create(name, description, rangeIPv4, gatewayIPv4, autoCreateSubnetworks);
return create(name, description, rangeIPv4, gatewayIPv4);
} }
} }

View File

@ -16,8 +16,6 @@
*/ */
package org.jclouds.googlecomputeengine.options; package org.jclouds.googlecomputeengine.options;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
@ -33,7 +31,8 @@ public abstract class SubnetworkCreationOptions {
public abstract String name(); public abstract String name();
@Nullable public abstract String description(); @Nullable
public abstract String description();
public abstract URI network(); public abstract URI network();
@ -41,12 +40,16 @@ public abstract class SubnetworkCreationOptions {
public abstract URI region(); public abstract URI region();
@SerializedNames({ "name", "description", "network", "ipCidrRange", "region" }) public abstract boolean privateIpGoogleAccess();
public static SubnetworkCreationOptions create(String name, String description, URI network,
String ipCidrRange, URI region) { @SerializedNames({ "name", "description", "network", "ipCidrRange", "region", "privateIpGoogleAccess" })
return new AutoValue_SubnetworkCreationOptions(name, description, network, ipCidrRange, region); public static SubnetworkCreationOptions create(String name, String description, URI network, String ipCidrRange,
URI region, boolean privateIpGoogleAccess) {
return new AutoValue_SubnetworkCreationOptions(name, description, network, ipCidrRange, region,
privateIpGoogleAccess);
} }
SubnetworkCreationOptions() { SubnetworkCreationOptions() {
} }
} }

View File

@ -173,6 +173,7 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
server.enqueue(jsonResponse("/image_list.json")); server.enqueue(jsonResponse("/image_list.json"));
server.enqueue(jsonResponse("/image_list_debian.json")); // per IMAGE_PROJECTS = "debian-cloud" server.enqueue(jsonResponse("/image_list_debian.json")); // per IMAGE_PROJECTS = "debian-cloud"
server.enqueue(jsonResponse("/aggregated_machinetype_list.json")); server.enqueue(jsonResponse("/aggregated_machinetype_list.json"));
server.enqueue(new MockResponse().setResponseCode(404)); // Get Subnet
server.enqueue(jsonResponse("/network_get_default.json")); server.enqueue(jsonResponse("/network_get_default.json"));
server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall
server.enqueue(jsonResponse("/operation.json")); // Create Firewall server.enqueue(jsonResponse("/operation.json")); // Create Firewall
@ -199,6 +200,7 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
assertSent(server, "GET", "/projects/party/global/images"); assertSent(server, "GET", "/projects/party/global/images");
assertSent(server, "GET", "/projects/debian-cloud/global/images"); assertSent(server, "GET", "/projects/debian-cloud/global/images");
assertSent(server, "GET", "/projects/party/aggregated/machineTypes"); assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
assertSent(server, "GET", "/projects/party/regions/us-central1/subnetworks/default");
assertSent(server, "GET", "/projects/party/global/networks/default"); assertSent(server, "GET", "/projects/party/global/networks/default");
assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall
@ -219,6 +221,7 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
server.enqueue(jsonResponse("/image_list.json")); server.enqueue(jsonResponse("/image_list.json"));
server.enqueue(jsonResponse("/image_list_debian.json")); // per IMAGE_PROJECTS = "debian-cloud" server.enqueue(jsonResponse("/image_list_debian.json")); // per IMAGE_PROJECTS = "debian-cloud"
server.enqueue(jsonResponse("/aggregated_machinetype_list.json")); server.enqueue(jsonResponse("/aggregated_machinetype_list.json"));
server.enqueue(new MockResponse().setResponseCode(404)); // Get Subnet
server.enqueue(jsonResponse("/network_get_default.json")); server.enqueue(jsonResponse("/network_get_default.json"));
server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall server.enqueue(new MockResponse().setResponseCode(404)); // Get Firewall
server.enqueue(jsonResponse("/operation.json")); // Create Firewall server.enqueue(jsonResponse("/operation.json")); // Create Firewall
@ -248,6 +251,7 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
assertSent(server, "GET", "/projects/party/global/images"); assertSent(server, "GET", "/projects/party/global/images");
assertSent(server, "GET", "/projects/debian-cloud/global/images"); assertSent(server, "GET", "/projects/debian-cloud/global/images");
assertSent(server, "GET", "/projects/party/aggregated/machineTypes"); assertSent(server, "GET", "/projects/party/aggregated/machineTypes");
assertSent(server, "GET", "/projects/party/regions/us-central1/subnetworks/default");
assertSent(server, "GET", "/projects/party/global/networks/default"); assertSent(server, "GET", "/projects/party/global/networks/default");
assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall
@ -263,6 +267,58 @@ public class GoogleComputeEngineServiceMockTest extends BaseGoogleComputeEngineA
assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-1"); assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-1");
} }
public void createNodeWithCustomSubnetwork() 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(jsonResponse("/subnetwork_get.json"));
server.enqueue(jsonResponse("/network_get.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));
server.enqueue(jsonResponse("/disk_get_with_source_image.json"));
server.enqueue(jsonResponse("/image_get_for_source_image.json"));
server.enqueue(jsonResponse("/disktype_ssd.json"));
server.enqueue(jsonResponse("/operation.json")); // Create Instance
server.enqueue(instanceWithNetworkAndStatusAndSsd("test-1", "test-network", RUNNING));
ComputeService computeService = computeService();
GoogleComputeEngineTemplateOptions options = computeService.templateOptions()
.as(GoogleComputeEngineTemplateOptions.class).autoCreateKeyPair(false)
.tags(ImmutableSet.of("aTag")).blockUntilRunning(false)
.bootDiskType("pd-ssd").networks("jclouds-test");
Template template = computeService.templateBuilder().options(options).build();
NodeMetadata node = getOnlyElement(computeService.createNodesInGroup("test", 1, template));
// prove our caching works.
assertEquals(node.getImageId(), template.getImage().getId());
assertEquals(node.getLocation().getId(), template.getLocation().getId());
assertSent(server, "GET", "/projects/party/regions");
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/regions/us-central1/subnetworks/jclouds-test");
assertSent(server, "GET", "/projects/party/global/networks/mynetwork");
assertSent(server, "GET", "/projects/party/global/firewalls/jclouds-test-65f"); // Get Firewall
assertSent(server, "POST", "/projects/party/global/firewalls", // Create Firewall
stringFromResource("/firewall_insert_3.json"));
assertSent(server, "GET", "/projects/party/zones/us-central1-a/operations/operation-1354084865060");
assertSent(server, "GET", "/projects/party/aggregated/instances");
assertSent(server, "GET", "/projects/party/zones/us-central1-a/disks/test");
assertSent(server, "GET", "/projects/debian-cloud/global/images/debian-7-wheezy-v20140718");
assertSent(server, "GET", "/projects/party/zones/us-central1-a/diskTypes/pd-ssd");
assertSent(server, "POST", "/projects/party/zones/us-central1-a/instances",
String.format(stringFromResource("/instance_insert_subnet.json"), template.getHardware().getId(), template.getImage().getId()));
assertSent(server, "GET", "/projects/party/zones/us-central1-a/instances/test-1");
}
private MockResponse instanceWithNetworkAndStatus(String instanceName, String networkName, Instance.Status status) { private MockResponse instanceWithNetworkAndStatus(String instanceName, String networkName, Instance.Status status) {
return new MockResponse().setBody( return new MockResponse().setBody(

View File

@ -24,12 +24,14 @@ import org.jclouds.googlecomputeengine.domain.Image;
import org.jclouds.googlecomputeengine.domain.Instance; import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.Network; import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Operation; import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.domain.Subnetwork;
import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiMockTest; import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiMockTest;
import org.jclouds.googlecomputeengine.parse.ParseDiskTest; import org.jclouds.googlecomputeengine.parse.ParseDiskTest;
import org.jclouds.googlecomputeengine.parse.ParseImageTest; import org.jclouds.googlecomputeengine.parse.ParseImageTest;
import org.jclouds.googlecomputeengine.parse.ParseInstanceTest; import org.jclouds.googlecomputeengine.parse.ParseInstanceTest;
import org.jclouds.googlecomputeengine.parse.ParseNetworkTest; import org.jclouds.googlecomputeengine.parse.ParseNetworkTest;
import org.jclouds.googlecomputeengine.parse.ParseOperationTest; import org.jclouds.googlecomputeengine.parse.ParseOperationTest;
import org.jclouds.googlecomputeengine.parse.ParseSubnetworkTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@Test(groups = "unit", testName = "ResourcesMockTest", singleThreaded = true) @Test(groups = "unit", testName = "ResourcesMockTest", singleThreaded = true)
@ -155,6 +157,22 @@ public class ResourcesMockTest extends BaseGoogleComputeEngineApiMockTest {
assertSent(server, "POST", "/foo/bar/start"); assertSent(server, "POST", "/foo/bar/start");
} }
public void testSubnetwork() throws Exception {
server.enqueue(jsonResponse("/subnetwork_get.json"));
Subnetwork subnet = resourceApi().subnetwork(server.getUrl("/foo/bar").toURI());
assertEquals(subnet, new ParseSubnetworkTest().expected(url("/projects")));
assertSent(server, "GET", "/foo/bar");
}
public void testSubnetworkReturns404() throws Exception {
server.enqueue(response404());
Subnetwork subnet = resourceApi().subnetwork(server.getUrl("/foo/bar").toURI());
assertNull(subnet);
assertSent(server, "GET", "/foo/bar");
}
private Resources resourceApi() { private Resources resourceApi() {
return builder().build().utils().injector().getInstance(Resources.class); return builder().build().utils().injector().getInstance(Resources.class);
} }

View File

@ -45,8 +45,7 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
@Test(groups = "live") @Test(groups = "live")
public void testInsertFirewall() { public void testInsertFirewall() {
// need to insert the network first // need to insert the network first
assertOperationDoneSuccessfully( assertOperationDoneSuccessfully(api.networks().createLegacy(FIREWALL_NETWORK_NAME, IPV4_RANGE));
api.networks().createInIPv4Range(FIREWALL_NETWORK_NAME, IPV4_RANGE));
FirewallOptions firewall = new FirewallOptions() FirewallOptions firewall = new FirewallOptions()
.addAllowedRule(Firewall.Rule.create("tcp", ImmutableList.of("22"))) .addAllowedRule(Firewall.Rule.create("tcp", ImmutableList.of("22")))

View File

@ -30,18 +30,18 @@ import java.util.Properties;
import org.jclouds.googlecloud.domain.ListPage; import org.jclouds.googlecloud.domain.ListPage;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.domain.AttachDisk;
import org.jclouds.googlecomputeengine.domain.Image; import org.jclouds.googlecomputeengine.domain.Image;
import org.jclouds.googlecomputeengine.domain.Instance; import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk; import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk;
import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig;
import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type; import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type;
import org.jclouds.googlecomputeengine.domain.Instance.Scheduling; import org.jclouds.googlecomputeengine.domain.Instance.Scheduling;
import org.jclouds.googlecomputeengine.domain.Instance.Scheduling.OnHostMaintenance; import org.jclouds.googlecomputeengine.domain.Instance.Scheduling.OnHostMaintenance;
import org.jclouds.googlecomputeengine.domain.Instance.SerialPortOutput; import org.jclouds.googlecomputeengine.domain.Instance.SerialPortOutput;
import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount; import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig;
import org.jclouds.googlecomputeengine.domain.Metadata; import org.jclouds.googlecomputeengine.domain.Metadata;
import org.jclouds.googlecomputeengine.domain.NewInstance; import org.jclouds.googlecomputeengine.domain.NewInstance;
import org.jclouds.googlecomputeengine.domain.AttachDisk;
import org.jclouds.googlecomputeengine.domain.Operation; import org.jclouds.googlecomputeengine.domain.Operation;
import org.jclouds.googlecomputeengine.domain.Tags; import org.jclouds.googlecomputeengine.domain.Tags;
import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
@ -96,6 +96,7 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
INSTANCE_NAME, // name INSTANCE_NAME, // name
getDefaultMachineTypeUrl(), // machineType getDefaultMachineTypeUrl(), // machineType
getNetworkUrl(INSTANCE_NETWORK_NAME), // network getNetworkUrl(INSTANCE_NETWORK_NAME), // network
null, // subnetwork
Arrays.asList(AttachDisk.newBootDisk(imageUri), Arrays.asList(AttachDisk.newBootDisk(imageUri),
AttachDisk.existingDisk(getDiskUrl(DISK_NAME))), // disks AttachDisk.existingDisk(getDiskUrl(DISK_NAME))), // disks
"a description", // description "a description", // description
@ -106,6 +107,7 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
instance2 = new NewInstance.Builder(INSTANCE_NAME2, // name instance2 = new NewInstance.Builder(INSTANCE_NAME2, // name
getDefaultMachineTypeUrl(), // machineType getDefaultMachineTypeUrl(), // machineType
getNetworkUrl(INSTANCE_NETWORK_NAME), // network getNetworkUrl(INSTANCE_NETWORK_NAME), // network
null, // subnetwork
imageUri) // sourceImage imageUri) // sourceImage
.canIpForward(true) .canIpForward(true)
.description("description") .description("description")
@ -141,8 +143,7 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
@Test(groups = "live") @Test(groups = "live")
public void testInsertInstance() { public void testInsertInstance() {
// need to insert the network first // need to insert the network first
assertOperationDoneSuccessfully(api.networks().createInIPv4Range assertOperationDoneSuccessfully(api.networks().createLegacy(INSTANCE_NETWORK_NAME, IPV4_RANGE));
(INSTANCE_NETWORK_NAME, IPV4_RANGE));
assertOperationDoneSuccessfully(diskApi().create(DISK_NAME, assertOperationDoneSuccessfully(diskApi().create(DISK_NAME,
new DiskCreationOptions.Builder().sizeGb(DEFAULT_DISK_SIZE_GB).build())); new DiskCreationOptions.Builder().sizeGb(DEFAULT_DISK_SIZE_GB).build()));

View File

@ -86,6 +86,7 @@ public class InstanceApiMockTest extends BaseGoogleComputeEngineApiMockTest {
"test-1", // name "test-1", // name
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType
URI.create(url("/projects/party/global/networks/default")), // network URI.create(url("/projects/party/global/networks/default")), // network
null, // subnetwork
URI.create(url("/projects/party/global/images/centos-6-2-v20120326")) // sourceImage URI.create(url("/projects/party/global/images/centos-6-2-v20120326")) // sourceImage
); );
@ -101,6 +102,7 @@ public class InstanceApiMockTest extends BaseGoogleComputeEngineApiMockTest {
"test-1", // name "test-1", // name
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType
URI.create(url("/projects/party/global/networks/default")), // network URI.create(url("/projects/party/global/networks/default")), // network
null, // subnetwork
Arrays.asList(AttachDisk.existingBootDisk(URI.create(url("/projects/party/zones/us-central1-a/disks/test")))), Arrays.asList(AttachDisk.existingBootDisk(URI.create(url("/projects/party/zones/us-central1-a/disks/test")))),
"desc", // description "desc", // description
null // tags null // tags
@ -270,6 +272,7 @@ public class InstanceApiMockTest extends BaseGoogleComputeEngineApiMockTest {
NewInstance newInstance = new NewInstance.Builder("test-1", // name NewInstance newInstance = new NewInstance.Builder("test-1", // name
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType
URI.create(url("/projects/party/global/networks/default")), // network URI.create(url("/projects/party/global/networks/default")), // network
null, // subnetwork
URI.create(url("/projects/party/global/images/centos-6-2-v20120326"))).build(); // sourceImage) URI.create(url("/projects/party/global/images/centos-6-2-v20120326"))).build(); // sourceImage)
assertEquals(instanceApi().create(newInstance), new ParseZoneOperationTest().expected(url("/projects"))); assertEquals(instanceApi().create(newInstance), new ParseZoneOperationTest().expected(url("/projects")));
@ -284,6 +287,7 @@ public class InstanceApiMockTest extends BaseGoogleComputeEngineApiMockTest {
"test-1", // name "test-1", // name
URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType URI.create(url("/projects/party/zones/us-central1-a/machineTypes/n1-standard-1")), // machineType
URI.create(url("/projects/party/global/networks/default")), // network URI.create(url("/projects/party/global/networks/default")), // network
null, // subnetwork
Arrays.asList(AttachDisk.existingBootDisk(URI.create(url("/projects/party/zones/us-central1-a/disks/test"))))) Arrays.asList(AttachDisk.existingBootDisk(URI.create(url("/projects/party/zones/us-central1-a/disks/test")))))
.canIpForward(true) .canIpForward(true)
.description("desc") .description("desc")

View File

@ -16,24 +16,8 @@
*/ */
package org.jclouds.googlecomputeengine.features; package org.jclouds.googlecomputeengine.features;
import com.google.common.base.Function; import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
import com.google.common.base.Predicate; import static org.testng.Assert.assertFalse;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.domain.Image;
import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.NewInstance;
import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
import org.jclouds.googlecomputeengine.options.DiskCreationOptions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import java.net.URI; import java.net.URI;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -44,8 +28,25 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter; import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
import static org.testng.Assert.assertFalse; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
import org.jclouds.googlecomputeengine.domain.Image;
import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.NewInstance;
import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
import org.jclouds.googlecomputeengine.options.DiskCreationOptions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
@Test(groups = "live", testName = "InstanceApiWindowsLiveTest") @Test(groups = "live", testName = "InstanceApiWindowsLiveTest")
public class InstanceApiWindowsLiveTest extends BaseGoogleComputeEngineApiLiveTest { public class InstanceApiWindowsLiveTest extends BaseGoogleComputeEngineApiLiveTest {
@ -80,6 +81,7 @@ public class InstanceApiWindowsLiveTest extends BaseGoogleComputeEngineApiLiveTe
INSTANCE_NAME, INSTANCE_NAME,
getDefaultMachineTypeUrl(), getDefaultMachineTypeUrl(),
getNetworkUrl(INSTANCE_NETWORK_NAME), getNetworkUrl(INSTANCE_NETWORK_NAME),
null,
imageUri imageUri
); );
@ -102,8 +104,7 @@ public class InstanceApiWindowsLiveTest extends BaseGoogleComputeEngineApiLiveTe
@Test(groups = "live") @Test(groups = "live")
public void testInsertInstanceWindows() { public void testInsertInstanceWindows() {
// need to insert the network first // need to insert the network first
assertOperationDoneSuccessfully(api.networks().createInIPv4Range assertOperationDoneSuccessfully(api.networks().createLegacy(INSTANCE_NETWORK_NAME, IPV4_RANGE));
(INSTANCE_NETWORK_NAME, IPV4_RANGE));
assertOperationDoneSuccessfully(diskApi().create(DISK_NAME, assertOperationDoneSuccessfully(diskApi().create(DISK_NAME,
new DiskCreationOptions.Builder().sizeGb(DEFAULT_DISK_SIZE_GB).build())); new DiskCreationOptions.Builder().sizeGb(DEFAULT_DISK_SIZE_GB).build()));

View File

@ -40,7 +40,7 @@ public class NetworkApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
@Test(groups = "live") @Test(groups = "live")
public void testInsertNetwork() { public void testInsertNetwork() {
assertOperationDoneSuccessfully(api().createInIPv4Range(NETWORK_NAME, IPV4_RANGE)); assertOperationDoneSuccessfully(api().createLegacy(NETWORK_NAME, IPV4_RANGE));
} }
@Test(groups = "live", dependsOnMethods = "testInsertNetwork") @Test(groups = "live", dependsOnMethods = "testInsertNetwork")

View File

@ -44,13 +44,21 @@ public class NetworkApiMockTest extends BaseGoogleComputeEngineApiMockTest {
assertSent(server, "GET", "/projects/party/global/networks/jclouds-test"); assertSent(server, "GET", "/projects/party/global/networks/jclouds-test");
} }
public void insert() throws Exception { public void insertLegacy() throws Exception {
server.enqueue(jsonResponse("/operation.json")); server.enqueue(jsonResponse("/operation.json"));
assertEquals(networkApi().createInIPv4Range("test-network", "10.0.0.0/8"), new ParseOperationTest().expected(url("/projects"))); assertEquals(networkApi().createLegacy("test-network", "10.0.0.0/8"), new ParseOperationTest().expected(url("/projects")));
assertSent(server, "POST", "/projects/party/global/networks", assertSent(server, "POST", "/projects/party/global/networks",
stringFromResource("/network_insert.json")); stringFromResource("/network_insert.json"));
} }
public void insertCustom() throws Exception {
server.enqueue(jsonResponse("/operation.json"));
assertEquals(networkApi().createCustom("test-network"), new ParseOperationTest().expected(url("/projects")));
assertSent(server, "POST", "/projects/party/global/networks",
stringFromResource("/network_insert_custom.json"));
}
public void delete() throws Exception { public void delete() throws Exception {
server.enqueue(jsonResponse("/operation.json")); server.enqueue(jsonResponse("/operation.json"));

View File

@ -43,8 +43,7 @@ public class RouteApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
@Test(groups = "live") @Test(groups = "live")
public void testInsertRoute() { public void testInsertRoute() {
assertOperationDoneSuccessfully(api.networks().createInIPv4Range assertOperationDoneSuccessfully(api.networks().createLegacy(ROUTE_NETWORK_NAME, IPV4_RANGE));
(ROUTE_NETWORK_NAME, IPV4_RANGE));
assertOperationDoneSuccessfully(api().createInNetwork(ROUTE_NAME, assertOperationDoneSuccessfully(api().createInNetwork(ROUTE_NAME,
getNetworkUrl(ROUTE_NETWORK_NAME), getNetworkUrl(ROUTE_NETWORK_NAME),
new RouteOptions().addTag("footag") new RouteOptions().addTag("footag")

View File

@ -0,0 +1,80 @@
/*
* 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.features;
import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import java.util.Iterator;
import java.util.List;
import org.jclouds.googlecloud.domain.ListPage;
import org.jclouds.googlecomputeengine.domain.Network;
import org.jclouds.googlecomputeengine.domain.Subnetwork;
import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
import org.jclouds.googlecomputeengine.options.SubnetworkCreationOptions;
import org.testng.annotations.Test;
@Test(groups = "live", testName = "SubnetworkApiLiveTest")
public class SubnetworkApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
private static final String SUBNETWORK_NAME = "subnetwork-api-live-test-network";
private static final String SUBNETWORK_RANGE = "10.0.0.0/8";
private SubnetworkApi api() {
return api.subnetworksInRegion(DEFAULT_REGION_NAME);
}
@Test
public void testInsertSubnetwork() {
assertOperationDoneSuccessfully(api.networks().createCustom(SUBNETWORK_NAME));
Network network = api.networks().get(SUBNETWORK_NAME);
assertNotNull(network);
SubnetworkCreationOptions opts = SubnetworkCreationOptions.create(SUBNETWORK_NAME, SUBNETWORK_NAME,
network.selfLink(), SUBNETWORK_RANGE, getDefaultRegionUrl(), false);
assertOperationDoneSuccessfully(api().createInNetwork(opts));
}
@Test(dependsOnMethods = "testInsertSubnetwork")
public void testGetSubnetwork() {
Subnetwork subnet = api().get(SUBNETWORK_NAME);
assertNotNull(subnet);
assertSubnetworkEquals(subnet);
}
@Test(dependsOnMethods = "testInsertSubnetwork")
public void testListSubnetworks() {
Iterator<ListPage<Subnetwork>> subnets = api().list(filter("name eq " + SUBNETWORK_NAME));
List<Subnetwork> subnetsAsList = subnets.next();
assertEquals(subnetsAsList.size(), 1);
assertSubnetworkEquals(subnetsAsList.get(0));
}
@Test(dependsOnMethods = { "testListSubnetworks", "testGetSubnetwork" }, alwaysRun = true)
public void testDeleteSubnetwork() {
assertOperationDoneSuccessfully(api().delete(SUBNETWORK_NAME));
assertOperationDoneSuccessfully(api.networks().delete(SUBNETWORK_NAME));
}
private void assertSubnetworkEquals(Subnetwork result) {
assertEquals(result.name(), SUBNETWORK_NAME);
assertEquals(result.ipCidrRange(), SUBNETWORK_RANGE);
}
}

View File

@ -55,7 +55,8 @@ public class SubnetworkApiMockTest extends BaseGoogleComputeEngineApiMockTest {
"my subnetwork", "my subnetwork",
URI.create(url("/projects/party/global/networks/mynetwork")), URI.create(url("/projects/party/global/networks/mynetwork")),
"10.0.0.0/24", "10.0.0.0/24",
URI.create(url("/projects/party/regions/someregion")))), new ParseOperationTest().expected(url("/projects"))); URI.create(url("/projects/party/regions/someregion")),
false)), new ParseOperationTest().expected(url("/projects")));
assertSent(server, "POST", "/projects/party/regions/someregion/subnetworks", assertSent(server, "POST", "/projects/party/regions/someregion/subnetworks",
stringFromResource("/subnetwork_insert.json")); stringFromResource("/subnetwork_insert.json"));
} }

View File

@ -69,11 +69,12 @@ public class TargetInstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTes
INSTANCE_NAME, // name INSTANCE_NAME, // name
getDefaultMachineTypeUrl(), // machineType getDefaultMachineTypeUrl(), // machineType
getNetworkUrl(INSTANCE_NETWORK_NAME), // network getNetworkUrl(INSTANCE_NETWORK_NAME), // network
null, // subnetwork
imageUri); imageUri);
// need to insert the network first // need to insert the network first
assertOperationDoneSuccessfully(api.networks().createInIPv4Range assertOperationDoneSuccessfully(api.networks().createLegacy(INSTANCE_NETWORK_NAME, IPV4_RANGE));
(INSTANCE_NETWORK_NAME, IPV4_RANGE));
assertOperationDoneSuccessfully(api.instancesInZone(DEFAULT_ZONE_NAME).create(newInstance)); assertOperationDoneSuccessfully(api.instancesInZone(DEFAULT_ZONE_NAME).create(newInstance));
instance = api.instancesInZone(DEFAULT_ZONE_NAME).get(INSTANCE_NAME); instance = api.instancesInZone(DEFAULT_ZONE_NAME).get(INSTANCE_NAME);
assertNotNull(instance); assertNotNull(instance);

View File

@ -26,13 +26,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.jclouds.googlecloud.domain.ListPage; import org.jclouds.googlecloud.domain.ListPage;
import org.jclouds.googlecomputeengine.domain.ForwardingRule.IPProtocol;
import org.jclouds.googlecomputeengine.domain.HealthStatus; import org.jclouds.googlecomputeengine.domain.HealthStatus;
import org.jclouds.googlecomputeengine.domain.HttpHealthCheck; import org.jclouds.googlecomputeengine.domain.HttpHealthCheck;
import org.jclouds.googlecomputeengine.domain.Image; import org.jclouds.googlecomputeengine.domain.Image;
import org.jclouds.googlecomputeengine.domain.Instance; import org.jclouds.googlecomputeengine.domain.Instance;
import org.jclouds.googlecomputeengine.domain.NewInstance; import org.jclouds.googlecomputeengine.domain.NewInstance;
import org.jclouds.googlecomputeengine.domain.TargetPool; import org.jclouds.googlecomputeengine.domain.TargetPool;
import org.jclouds.googlecomputeengine.domain.ForwardingRule.IPProtocol;
import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
import org.jclouds.googlecomputeengine.options.ForwardingRuleCreationOptions; import org.jclouds.googlecomputeengine.options.ForwardingRuleCreationOptions;
import org.jclouds.googlecomputeengine.options.HttpHealthCheckCreationOptions; import org.jclouds.googlecomputeengine.options.HttpHealthCheckCreationOptions;
@ -84,9 +84,8 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
}) })
.first().get().selfLink(); .first().get().selfLink();
// Insert a network. // need to insert the network first
assertOperationDoneSuccessfully(api.networks().createInIPv4Range(INSTANCE_NETWORK_NAME, assertOperationDoneSuccessfully(api.networks().createLegacy(INSTANCE_NETWORK_NAME, IPV4_RANGE));
IPV4_RANGE));
// Create an instance. // Create an instance.
assertOperationDoneSuccessfully( assertOperationDoneSuccessfully(
@ -94,6 +93,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
INSTANCE_NAME, // name INSTANCE_NAME, // name
getDefaultMachineTypeUrl(), // machineType getDefaultMachineTypeUrl(), // machineType
getNetworkUrl(INSTANCE_NETWORK_NAME), // network getNetworkUrl(INSTANCE_NETWORK_NAME), // network
null, // subnetwork
imageUri // disks imageUri // disks
))); )));

View File

@ -48,6 +48,7 @@ public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest<GoogleCo
protected static final String ZONE_API_URL_SUFFIX = "/zones/"; protected static final String ZONE_API_URL_SUFFIX = "/zones/";
protected static final String DEFAULT_ZONE_NAME = "us-central1-f"; protected static final String DEFAULT_ZONE_NAME = "us-central1-f";
protected static final String REGION_API_URL_SUFFIX = "/regions/";
protected static final String DEFAULT_REGION_NAME = "us-central1"; protected static final String DEFAULT_REGION_NAME = "us-central1";
protected static final String NETWORK_API_URL_SUFFIX = "/global/networks/"; protected static final String NETWORK_API_URL_SUFFIX = "/global/networks/";
protected static final String MACHINE_TYPE_API_URL_SUFFIX = "/machineTypes/"; protected static final String MACHINE_TYPE_API_URL_SUFFIX = "/machineTypes/";
@ -116,6 +117,14 @@ public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest<GoogleCo
protected URI getZoneUrl(String zone) { protected URI getZoneUrl(String zone) {
return URI.create(projectUrl + ZONE_API_URL_SUFFIX + zone); return URI.create(projectUrl + ZONE_API_URL_SUFFIX + zone);
} }
protected URI getDefaultRegionUrl() {
return getRegionUrl(DEFAULT_REGION_NAME);
}
protected URI getRegionUrl(String region) {
return URI.create(projectUrl + REGION_API_URL_SUFFIX + region);
}
protected URI getNetworkUrl(String network) { protected URI getNetworkUrl(String network) {
return URI.create(projectUrl + NETWORK_API_URL_SUFFIX + network); return URI.create(projectUrl + NETWORK_API_URL_SUFFIX + network);
@ -162,5 +171,9 @@ public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest<GoogleCo
protected URI getUrlMapUrl(String urlMap) { protected URI getUrlMapUrl(String urlMap) {
return URI.create(projectUrl + URL_MAP_API_URL_SUFFIX + urlMap); return URI.create(projectUrl + URL_MAP_API_URL_SUFFIX + urlMap);
} }
protected URI getSubnetworkUrl(String region, String subnetName) {
return URI.create(projectUrl + REGION_API_URL_SUFFIX + region + "/subnetworks/" + subnetName);
}
} }

View File

@ -19,6 +19,7 @@ package org.jclouds.googlecomputeengine.parse;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import java.net.URI; import java.net.URI;
import java.util.Collections;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -48,7 +49,9 @@ public class ParseNetworkTest extends BaseGoogleComputeEngineParseTest<Network>
"jclouds-test", // name "jclouds-test", // name
"A custom network for the project", // description "A custom network for the project", // description
"10.0.0.0/8", // rangeIPv4 "10.0.0.0/8", // rangeIPv4
"10.0.0.1" // gatewayIPv4 "10.0.0.1", // gatewayIPv4
false,
Collections.<URI> emptyList() // subnetworks
); );
} }
} }

View File

@ -33,7 +33,7 @@ public class ParseSubnetworkListTest extends BaseGoogleComputeEngineParseTest<Li
@Override @Override
public String resource() { public String resource() {
return "/network_list.json"; return "/subnetwork_list.json";
} }
@Override @Consumes(APPLICATION_JSON) @Override @Consumes(APPLICATION_JSON)

View File

@ -31,7 +31,7 @@ public class ParseSubnetworkTest extends BaseGoogleComputeEngineParseTest<Subnet
@Override @Override
public String resource() { public String resource() {
return "/network_get.json"; return "/subnetwork_get.json";
} }
@Override @Consumes(APPLICATION_JSON) @Override @Consumes(APPLICATION_JSON)
@ -45,7 +45,7 @@ public class ParseSubnetworkTest extends BaseGoogleComputeEngineParseTest<Subnet
"5850679262666457680", // id "5850679262666457680", // id
parse("2016-06-07T14:29:35.476-07:00"), // creationTimestamp parse("2016-06-07T14:29:35.476-07:00"), // creationTimestamp
URI.create(baseUrl + "/party/regions/someregion/subnetworks/jclouds-test"), // selfLink URI.create(baseUrl + "/party/regions/someregion/subnetworks/jclouds-test"), // selfLink
"jclouds-subnetwork-test", // name "jclouds-test", // name
"A custom subnetwork for the project", // description "A custom subnetwork for the project", // description
"10.128.0.1", "10.128.0.1",
URI.create(baseUrl + "/party/global/networks/mynetwork"), // network URI.create(baseUrl + "/party/global/networks/mynetwork"), // network

View File

@ -0,0 +1,28 @@
{
"name": "jclouds-test-65f",
"network": "https://www.googleapis.com/compute/v1/projects/party/networks/jclouds-test",
"sourceRanges": [
"10.128.0.0/20",
"0.0.0.0/0"
],
"sourceTags": [
"aTag"
],
"targetTags": [
"jclouds-test-65f"
],
"allowed": [
{
"IPProtocol": "tcp",
"ports": [
"22"
]
},
{
"IPProtocol": "udp",
"ports": [
"22"
]
}
]
}

View File

@ -0,0 +1,46 @@
{
"machineType": "%s",
"name": "test-1",
"networkInterfaces": [
{
"network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork",
"subnetwork": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion/subnetworks/jclouds-test",
"accessConfigs": [
{
"type": "ONE_TO_ONE_NAT"
}
]
}
],
"disks": [
{
"type": "PERSISTENT",
"initializeParams": {
"sourceImage": "%s",
"diskType": "https://content.googleapis.com/compute/v1/projects/party/zones/us-central1-a/diskTypes/pd-ssd"
},
"boot": true,
"autoDelete": true
}
],
"description": "test",
"tags": {
"items": [
"aTag",
"jclouds-test-65f"
]
},
"metadata": {
"items": [
{
"key": "jclouds-group",
"value": "test"
}
]
},
"scheduling": {
"onHostMaintenance": "MIGRATE",
"automaticRestart": true,
"preemptible": false
}
}

View File

@ -6,5 +6,6 @@
"name": "jclouds-test", "name": "jclouds-test",
"description": "A custom network for the project", "description": "A custom network for the project",
"IPv4Range": "10.0.0.0/8", "IPv4Range": "10.0.0.0/8",
"gatewayIPv4": "10.0.0.1" "gatewayIPv4": "10.0.0.1",
"subnetworks": []
} }

View File

@ -0,0 +1 @@
{"autoCreateSubnetworks":false,"name":"test-network"}

View File

@ -3,7 +3,7 @@
"id": "5850679262666457680", "id": "5850679262666457680",
"creationTimestamp": "2016-06-07T14:29:35.476-07:00", "creationTimestamp": "2016-06-07T14:29:35.476-07:00",
"gatewayAddress": "10.128.0.1", "gatewayAddress": "10.128.0.1",
"name": "jclouds-subnetwork-test", "name": "jclouds-test",
"network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork", "network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork",
"ipCidrRange": "10.128.0.0/20", "ipCidrRange": "10.128.0.0/20",
"region": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion", "region": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion",

View File

@ -3,5 +3,6 @@
"description": "my subnetwork", "description": "my subnetwork",
"network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork", "network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork",
"ipCidrRange": "10.0.0.0/24", "ipCidrRange": "10.0.0.0/24",
"region": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion" "region": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion",
"privateIpGoogleAccess": false
} }

View File

@ -8,7 +8,7 @@
"id": "5850679262666457680", "id": "5850679262666457680",
"creationTimestamp": "2016-06-07T14:29:35.476-07:00", "creationTimestamp": "2016-06-07T14:29:35.476-07:00",
"gatewayAddress": "10.128.0.1", "gatewayAddress": "10.128.0.1",
"name": "jclouds-subnetwork-test", "name": "jclouds-test",
"network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork", "network": "https://www.googleapis.com/compute/v1/projects/party/global/networks/mynetwork",
"ipCidrRange": "10.128.0.0/20", "ipCidrRange": "10.128.0.0/20",
"region": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion", "region": "https://www.googleapis.com/compute/v1/projects/party/regions/someregion",