diff --git a/providers/google-compute-engine/pom.xml b/providers/google-compute-engine/pom.xml index 375192c892..de8d7595dd 100644 --- a/providers/google-compute-engine/pom.xml +++ b/providers/google-compute-engine/pom.xml @@ -114,6 +114,9 @@ test + + **/GoogleComputeEngineSecurityGroupExtensionLiveTest.java + ${test.google-compute-engine.identity} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java index 1e3580be7e..b726f11a09 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java @@ -35,32 +35,43 @@ import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.config.ComputeServiceAdapterContextModule; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.SecurityGroup; import org.jclouds.compute.extensions.ImageExtension; +import org.jclouds.compute.extensions.SecurityGroupExtension; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate; import org.jclouds.domain.Location; import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineService; import org.jclouds.googlecomputeengine.compute.GoogleComputeEngineServiceAdapter; +import org.jclouds.googlecomputeengine.compute.extensions.GoogleComputeEngineSecurityGroupExtension; import org.jclouds.googlecomputeengine.compute.functions.BuildInstanceMetadata; +import org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermission; import org.jclouds.googlecomputeengine.compute.functions.GoogleComputeEngineImageToImage; import org.jclouds.googlecomputeengine.compute.functions.InstanceInZoneToNodeMetadata; import org.jclouds.googlecomputeengine.compute.functions.MachineTypeInZoneToHardware; +import org.jclouds.googlecomputeengine.compute.functions.NetworkToSecurityGroup; import org.jclouds.googlecomputeengine.compute.functions.OrphanedGroupsFromDeadNodes; import org.jclouds.googlecomputeengine.compute.functions.RegionToLocation; import org.jclouds.googlecomputeengine.compute.functions.ZoneToLocation; +import org.jclouds.googlecomputeengine.compute.loaders.FindNetworkOrCreate; import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions; import org.jclouds.googlecomputeengine.compute.predicates.AllNodesInGroupTerminated; import org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.googlecomputeengine.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; import org.jclouds.googlecomputeengine.compute.strategy.UseNodeCredentialsButOverrideFromTemplate; import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; import org.jclouds.googlecomputeengine.domain.Image; import org.jclouds.googlecomputeengine.domain.Instance; import org.jclouds.googlecomputeengine.domain.InstanceInZone; import org.jclouds.googlecomputeengine.domain.MachineTypeInZone; +import org.jclouds.googlecomputeengine.domain.Network; import org.jclouds.googlecomputeengine.domain.Region; import org.jclouds.googlecomputeengine.domain.Zone; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.functions.CreateNetworkIfNeeded; +import org.jclouds.net.domain.IpPermission; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; @@ -69,6 +80,9 @@ import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.inject.Injector; import com.google.inject.Provides; @@ -105,6 +119,12 @@ public class GoogleComputeEngineServiceContextModule bind(new TypeLiteral>() {}) .to(ZoneToLocation.class); + bind(new TypeLiteral>>() {}) + .to(FirewallToIpPermission.class); + + bind(new TypeLiteral>() {}) + .to(NetworkToSecurityGroup.class); + bind(new TypeLiteral>>() {}) .to(BuildInstanceMetadata.class); @@ -121,6 +141,15 @@ public class GoogleComputeEngineServiceContextModule bind(new TypeLiteral>() {}).to(AllNodesInGroupTerminated.class); + bind(new TypeLiteral>() {}) + .to(CreateNetworkIfNeeded.class); + + bind(new TypeLiteral>() {}) + .to(FindNetworkOrCreate.class); + + bind(new TypeLiteral() {}) + .to(GoogleComputeEngineSecurityGroupExtension.class); + bind(PrioritizeCredentialsFromTemplate.class).to(UseNodeCredentialsButOverrideFromTemplate.class); install(new LocationsFromComputeServiceAdapterModule() {}); @@ -131,7 +160,7 @@ public class GoogleComputeEngineServiceContextModule @Singleton @Memoized public Supplier> provideImagesMap( - AtomicReference authException, + AtomicReference authException, final Supplier> images, @Named(PROPERTY_SESSION_INTERVAL) long seconds) { return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, @@ -219,11 +248,23 @@ public class GoogleComputeEngineServiceContextModule seconds, TimeUnit.SECONDS); } + @Provides + @Singleton + protected LoadingCache networkMap( + CacheLoader in) { + return CacheBuilder.newBuilder().build(in); + } + @Override protected Optional provideImageExtension(Injector i) { return Optional.absent(); } + @Override + protected Optional provideSecurityGroupExtension(Injector i) { + return Optional.of(i.getInstance(SecurityGroupExtension.class)); + } + @VisibleForTesting public static final Map toPortableNodeStatus = ImmutableMap.builder() diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java new file mode 100644 index 0000000000..2ceccef814 --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java @@ -0,0 +1,340 @@ +/* + * 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.extensions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.DEFAULT_INTERNAL_NETWORK_RANGE; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.equalsIpPermission; +import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.providesIpPermission; +import static org.jclouds.util.Predicates2.retry; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.extensions.SecurityGroupExtension; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.domain.Location; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Instance; +import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.SlashEncodedIds; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.googlecomputeengine.options.ListOptions.Builder; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; + +/** + * An extension to compute service to allow for the manipulation of {@link org.jclouds.compute.domain.SecurityGroup}s. Implementation + * is optional by providers. + * + * @author Andrew Bayer + */ +public class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupExtension { + + protected final Supplier userProject; + protected final GroupNamingConvention.Factory namingConvention; + protected final LoadingCache networkCreator; + protected final Function groupConverter; + protected final GoogleComputeEngineApi api; + protected final Predicate> operationDonePredicate; + protected final long operationCompleteCheckInterval; + protected final long operationCompleteCheckTimeout; + + @Inject + public GoogleComputeEngineSecurityGroupExtension(GoogleComputeEngineApi api, + @UserProject Supplier userProject, + GroupNamingConvention.Factory namingConvention, + LoadingCache networkCreator, + Function groupConverter, + @Named("global") Predicate> operationDonePredicate, + @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) { + this.api = checkNotNull(api, "api"); + this.userProject = checkNotNull(userProject, "userProject"); + this.namingConvention = checkNotNull(namingConvention, "namingConvention"); + this.networkCreator = checkNotNull(networkCreator, "networkCreator"); + this.groupConverter = checkNotNull(groupConverter, "groupConverter"); + this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval, + "operation completed check interval"); + this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, + "operation completed check timeout"); + this.operationDonePredicate = operationDonePredicate; + } + + @Override + public Set listSecurityGroups() { + return api.getNetworkApiForProject(userProject.get()).list().concat().transform(groupConverter).toSet(); + } + + @Override + public Set listSecurityGroupsInLocation(final Location location) { + return listSecurityGroups(); + } + + @Override + public Set listSecurityGroupsForNode(String id) { + SlashEncodedIds slashEncodedIds = SlashEncodedIds.fromSlashEncoded(id); + + Instance instance = api.getInstanceApiForProject(userProject.get()).getInZone(slashEncodedIds.getFirstId(), + slashEncodedIds.getSecondId()); + + if (instance == null) { + return ImmutableSet.of(); + } + + ImmutableSet.Builder builder = ImmutableSet.builder(); + + + for (NetworkInterface nwInterface : instance.getNetworkInterfaces()) { + String networkUrl = nwInterface.getNetwork().getPath(); + Network nw = api.getNetworkApiForProject(userProject.get()).get(networkUrl.substring(networkUrl.lastIndexOf('/') + 1)); + + SecurityGroup grp = groupForTagsInNetwork(nw, instance.getTags().getItems()); + if (grp != null) { + builder.add(grp); + } + } + + return builder.build(); + } + + @Override + public SecurityGroup getSecurityGroupById(String id) { + checkNotNull(id, "id"); + Network network = api.getNetworkApiForProject(userProject.get()).get(id); + + if (network == null) { + return null; + } + + return groupConverter.apply(network); + } + + @Override + public SecurityGroup createSecurityGroup(String name, Location location) { + return createSecurityGroup(name); + } + + public SecurityGroup createSecurityGroup(String name) { + checkNotNull(name, "name"); + + NetworkAndAddressRange nAr = new NetworkAndAddressRange(name, DEFAULT_INTERNAL_NETWORK_RANGE, null); + + Network nw = networkCreator.apply(nAr); + + return groupConverter.apply(nw); + } + + @Override + public boolean removeSecurityGroup(String id) { + checkNotNull(id, "id"); + if (api.getNetworkApiForProject(userProject.get()).get(id) == null) { + return false; + } + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + id); + + FluentIterable fws = api.getFirewallApiForProject(userProject.get()).list(options).concat(); + + for (Firewall fw : fws) { + AtomicReference operation = new AtomicReference(api.getFirewallApiForProject(userProject.get()) + .delete(fw.getName())); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not delete firewall, operation failed" + operation); + } + + AtomicReference operation = new AtomicReference( + api.getNetworkApiForProject(userProject.get()).delete(id)); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create network, operation failed" + operation); + + return true; + } + + @Override + public SecurityGroup addIpPermission(IpPermission ipPermission, SecurityGroup group) { + + if (api.getNetworkApiForProject(userProject.get()).get(group.getId()) == null) { + // Network corresponding to security group does not exist. + return null; + } + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + group.getName()); + + if (api.getFirewallApiForProject(userProject.get()).list(options).concat().anyMatch(providesIpPermission(ipPermission))) { + // Permission already exists. + return group; + } + + FirewallOptions fwOptions = new FirewallOptions(); + String uniqueFwName = namingConvention.createWithoutPrefix().uniqueNameForGroup(group.getName()); + fwOptions.name(uniqueFwName); + fwOptions.network(group.getUri()); + if (ipPermission.getGroupIds().size() > 0) { + fwOptions.sourceTags(ipPermission.getGroupIds()); + } + if (ipPermission.getCidrBlocks().size() > 0) { + fwOptions.sourceRanges(ipPermission.getCidrBlocks()); + } + Firewall.Rule.Builder ruleBuilder = Firewall.Rule.builder(); + ruleBuilder.IpProtocol(ipPermission.getIpProtocol()); + if (ipPermission.getToPort() > 0) { + ruleBuilder.addPortRange(ipPermission.getFromPort(), ipPermission.getToPort()); + } + fwOptions.addAllowedRule(ruleBuilder.build()); + + AtomicReference operation = new AtomicReference(api.getFirewallApiForProject(userProject + .get()).createInNetwork( + uniqueFwName, + group.getUri(), + fwOptions)); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create firewall, operation failed" + operation); + + return getSecurityGroupById(group.getId()); + } + + @Override + public SecurityGroup addIpPermission(IpProtocol protocol, int startPort, int endPort, + Multimap tenantIdGroupNamePairs, Iterable ipRanges, + Iterable groupIds, SecurityGroup group) { + + IpPermission.Builder permBuilder = IpPermission.builder(); + permBuilder.ipProtocol(protocol); + permBuilder.fromPort(startPort); + permBuilder.toPort(endPort); + permBuilder.groupIds(groupIds); + permBuilder.cidrBlocks(ipRanges); + + return addIpPermission(permBuilder.build(), group); + + } + + @Override + public SecurityGroup removeIpPermission(IpPermission ipPermission, SecurityGroup group) { + if (api.getNetworkApiForProject(userProject.get()).get(group.getId()) == null) { + // Network corresponding to security group does not exist. + return null; + } + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + group.getName()); + + FluentIterable fws = api.getFirewallApiForProject(userProject.get()).list(options).concat(); + + for (Firewall fw : fws) { + if (equalsIpPermission(ipPermission).apply(fw)) { + AtomicReference operation = new AtomicReference(api.getFirewallApiForProject(userProject.get()) + .delete(fw.getName())); + + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not delete firewall, operation failed" + operation); + } + } + + return getSecurityGroupById(group.getId()); + } + + @Override + public SecurityGroup removeIpPermission(IpProtocol protocol, int startPort, int endPort, + Multimap tenantIdGroupNamePairs, Iterable ipRanges, + Iterable groupIds, SecurityGroup group) { + + IpPermission.Builder permBuilder = IpPermission.builder(); + permBuilder.ipProtocol(protocol); + permBuilder.fromPort(startPort); + permBuilder.toPort(endPort); + permBuilder.groupIds(groupIds); + permBuilder.cidrBlocks(ipRanges); + + return removeIpPermission(permBuilder.build(), group); + + } + + @Override + public boolean supportsTenantIdGroupNamePairs() { + return false; + } + + @Override + public boolean supportsTenantIdGroupIdPairs() { + return false; + } + + @Override + public boolean supportsGroupIds() { + return true; + } + + @Override + public boolean supportsPortRangesForGroups() { + return true; + } + + private SecurityGroup groupForTagsInNetwork(Network nw, final Set tags) { + ListOptions opts = new Builder().filter("network eq .*/" + nw.getName()); + Set fws = api.getFirewallApiForProject(userProject.get()).list(opts).concat() + .filter(new Predicate() { + @Override + public boolean apply(final Firewall input) { + // If any of the targetTags on the firewall apply or the firewall has no target tags... + return Iterables.any(input.getTargetTags(), Predicates.in(tags)) + || Predicates.equalTo(0).apply(input.getTargetTags().size()); + } + }).toSet(); + + if (fws.size() > 0) { + return groupConverter.apply(nw); + } + + return null; + } +} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermission.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermission.java new file mode 100644 index 0000000000..6ee86f9dde --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermission.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.googlecomputeengine.compute.functions; + +import javax.annotation.Resource; +import javax.inject.Named; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Firewall.Rule; +import org.jclouds.logging.Logger; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Range; + +/** + * A function for transforming a GCE-specific Firewall into a generic + * IpPermission object. + * + * @author Andrew Bayer + */ +public class FirewallToIpPermission implements Function> { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + public FirewallToIpPermission() { + } + + + @Override + public Iterable apply(Firewall fw) { + ImmutableSet.Builder setBuilder = ImmutableSet.builder(); + + for (Rule rule: fw.getAllowed()) { + if (!rule.getPorts().isEmpty()) { + for (Range r : rule.getPorts().asRanges()) { + IpPermission.Builder builder = populateBuilder(fw, rule.getIpProtocol()); + builder.fromPort(r.lowerEndpoint()); + builder.toPort(r.upperEndpoint()); + setBuilder.add(builder.build()); + } + } else { + setBuilder.add(populateBuilder(fw, rule.getIpProtocol()).build()); + } + } + + return setBuilder.build(); + } + + /** + * Convenience method for populating common parts of the IpPermission. + * @param fw + * @param protocol + * @return a pre-populated builder. + */ + private IpPermission.Builder populateBuilder(Firewall fw, IpProtocol protocol) { + IpPermission.Builder builder = IpPermission.builder(); + + builder.ipProtocol(protocol); + + if (!fw.getSourceRanges().isEmpty()) { + builder.cidrBlocks(fw.getSourceRanges()); + } + if (!fw.getSourceTags().isEmpty()) { + builder.groupIds(fw.getSourceTags()); + } + + return builder; + } +} + diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java new file mode 100644 index 0000000000..ad8a95cb0f --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroup.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.googlecomputeengine.compute.functions; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.compute.domain.SecurityGroupBuilder; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.logging.Logger; +import org.jclouds.net.domain.IpPermission; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; + +/** + * A function for transforming a GCE-specific Network into a generic + * SecurityGroup object. + * + * @author Andrew Bayer + */ +public class NetworkToSecurityGroup implements Function { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final Function> firewallToPerms; + private final GoogleComputeEngineApi api; + private final Supplier project; + + @Inject + public NetworkToSecurityGroup(Function> firewallToPerms, + GoogleComputeEngineApi api, + @UserProject Supplier project) { + this.firewallToPerms = firewallToPerms; + this.api = api; + this.project = project; + } + + @Override + public SecurityGroup apply(Network network) { + SecurityGroupBuilder builder = new SecurityGroupBuilder(); + + builder.id(network.getName()); + builder.providerId(network.getId()); + builder.name(network.getName()); + builder.uri(network.getSelfLink()); + + ImmutableSet.Builder permBuilder = ImmutableSet.builder(); + + ListOptions options = new ListOptions.Builder().filter("network eq .*/" + network.getName()); + + for (Firewall fw : api.getFirewallApiForProject(project.get()).list(options).concat()) { + permBuilder.addAll(firewallToPerms.apply(fw)); + } + + builder.ipPermissions(permBuilder.build()); + + return builder.build(); + } +} + diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreate.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreate.java new file mode 100644 index 0000000000..120448f29b --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreate.java @@ -0,0 +1,65 @@ +/* + * 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.loaders; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheLoader; + +/** + * @author Andrew Bayer + */ +public class FindNetworkOrCreate extends CacheLoader { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + protected final GoogleComputeEngineApi api; + protected final Function networkCreator; + protected final Supplier userProject; + + @Inject + public FindNetworkOrCreate(GoogleComputeEngineApi api, + Function networkCreator, + @UserProject Supplier userProject) { + this.api = checkNotNull(api, "api"); + this.networkCreator = checkNotNull(networkCreator, "networkCreator"); + this.userProject = checkNotNull(userProject, "userProject"); + } + + @Override + public Network load(NetworkAndAddressRange in) { + Network network = api.getNetworkApiForProject(userProject.get()).get(in.getName()); + if (network != null) { + return network; + } else { + return networkCreator.apply(in); + } + } +} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java index 53803131bb..74059f9dc9 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java @@ -45,10 +45,13 @@ import org.jclouds.googlecomputeengine.config.UserProject; import org.jclouds.googlecomputeengine.domain.Firewall; import org.jclouds.googlecomputeengine.domain.Network; import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; import org.jclouds.googlecomputeengine.options.FirewallOptions; +import org.jclouds.net.domain.IpProtocol; import com.google.common.base.Predicate; import com.google.common.base.Supplier; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.ListenableFuture; @@ -65,6 +68,7 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends private final GoogleComputeEngineApi api; private final Supplier userProject; + private final LoadingCache networkMap; private final Predicate> operationDonePredicate; private final long operationCompleteCheckInterval; private final long operationCompleteCheckTimeout; @@ -82,7 +86,8 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends @UserProject Supplier userProject, @Named("global") Predicate> operationDonePredicate, @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, - @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) { + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout, + LoadingCache networkMap) { super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor, customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); @@ -93,6 +98,7 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, "operation completed check timeout"); this.operationDonePredicate = operationDonePredicate; + this.networkMap = checkNotNull(networkMap, "networkMap"); } @Override @@ -123,31 +129,13 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends String networkName = templateOptions.getNetworkName().or(sharedResourceName); - // check if the network was previously created (cache???) - Network network = api.getNetworkApiForProject(userProject.get()).get(networkName); - - if (network != null) { - return network; - } else if (templateOptions.getNetwork().isPresent()) { - throw new IllegalArgumentException("requested network " + networkName + " does not exist"); - } - - AtomicReference operation = new AtomicReference(api.getNetworkApiForProject(userProject - .get()).createInIPv4Range(sharedResourceName, DEFAULT_INTERNAL_NETWORK_RANGE)); - retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, - MILLISECONDS).apply(operation); - - checkState(!operation.get().getHttpError().isPresent(), "Could not create network, operation failed" + operation); - - return checkNotNull(api.getNetworkApiForProject(userProject.get()).get(sharedResourceName), - "no network with name %s was found", sharedResourceName); - + return networkMap.apply(new NetworkAndAddressRange(networkName, DEFAULT_INTERNAL_NETWORK_RANGE, null)); } /** * Tries to find if a firewall already exists for this group, if not it creates one. * - * @see org.jclouds.googlecomputeengine.features.FirewallAsyncApi#patch(String, org.jclouds.googlecomputeengine.options.FirewallOptions) + * @see org.jclouds.googlecomputeengine.features.FirewallApi#patch(String, org.jclouds.googlecomputeengine.options.FirewallOptions) */ private void getOrCreateFirewall(GoogleComputeEngineTemplateOptions templateOptions, Network network, String sharedResourceName) { @@ -161,9 +149,9 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends ImmutableSet.Builder rules = ImmutableSet.builder(); Firewall.Rule.Builder tcpRule = Firewall.Rule.builder(); - tcpRule.IPProtocol(Firewall.Rule.IPProtocol.TCP); + tcpRule.IpProtocol(IpProtocol.TCP); Firewall.Rule.Builder udpRule = Firewall.Rule.builder(); - udpRule.IPProtocol(Firewall.Rule.IPProtocol.UDP); + udpRule.IpProtocol(IpProtocol.UDP); for (Integer port : templateOptions.getInboundPorts()) { tcpRule.addPort(port); udpRule.addPort(port); diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java index 1b3fbac29f..ef9d7d6322 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineParserModule.java @@ -36,6 +36,7 @@ import org.jclouds.googlecomputeengine.domain.Project; import org.jclouds.googlecomputeengine.options.FirewallOptions; import org.jclouds.googlecomputeengine.options.RouteOptions; import org.jclouds.json.config.GsonModule; +import org.jclouds.net.domain.IpProtocol; import org.jclouds.oauth.v2.domain.ClaimSet; import org.jclouds.oauth.v2.domain.Header; import org.jclouds.oauth.v2.json.ClaimSetTypeAdapter; @@ -380,7 +381,7 @@ public class GoogleComputeEngineParserModule extends AbstractModule { JsonParseException { JsonObject rule = json.getAsJsonObject(); Rule.Builder builder = Rule.builder(); - builder.IPProtocol(Rule.IPProtocol.fromValue(rule.get("IPProtocol").getAsString())); + builder.IpProtocol(IpProtocol.fromValue(rule.get("IPProtocol").getAsString())); if (rule.get("ports") != null) { JsonArray ports = (JsonArray) rule.get("ports"); for (JsonElement port : ports) { @@ -399,7 +400,7 @@ public class GoogleComputeEngineParserModule extends AbstractModule { @Override public JsonElement serialize(Firewall.Rule src, Type typeOfSrc, JsonSerializationContext context) { JsonObject ruleObject = new JsonObject(); - ruleObject.addProperty("IPProtocol", src.getIPProtocol().value()); + ruleObject.addProperty("IPProtocol", src.getIpProtocol().value()); if (src.getPorts() != null && !src.getPorts().isEmpty()) { JsonArray ports = new JsonArray(); for (Range range : src.getPorts().asRanges()) { diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java index 52d51abb2d..78874bc094 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Firewall.java @@ -28,6 +28,8 @@ import java.net.URI; import java.util.Date; import java.util.Set; +import org.jclouds.net.domain.IpProtocol; + import com.google.common.annotations.Beta; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; @@ -245,32 +247,14 @@ public final class Firewall extends Resource { */ public static final class Rule { - public enum IPProtocol { - - TCP, UDP, ICMP, UNKNOWN; - - public String value() { - return name().toLowerCase(); - } - - @Override - public String toString() { - return value(); - } - - public static IPProtocol fromValue(String protocol) { - return valueOf(protocol.toUpperCase()); - } - } - - private final IPProtocol ipProtocol; + private final IpProtocol ipProtocol; private final RangeSet ports; @ConstructorProperties({ - "IPProtocol", "ports" + "IpProtocol", "ports" }) - private Rule(IPProtocol IPProtocol, RangeSet ports) { - this.ipProtocol = checkNotNull(IPProtocol); + private Rule(IpProtocol IpProtocol, RangeSet ports) { + this.ipProtocol = checkNotNull(IpProtocol); this.ports = ports == null ? TreeRangeSet.create() : ports; } @@ -279,7 +263,7 @@ public final class Firewall extends Resource { * * @return this is the IP protocol that is allowed for this rule. */ - public IPProtocol getIPProtocol() { + public IpProtocol getIpProtocol() { return ipProtocol; } @@ -320,7 +304,7 @@ public final class Firewall extends Resource { */ public Objects.ToStringHelper string() { return toStringHelper(this) - .add("IPProtocol", ipProtocol).add("ports", ports); + .add("IpProtocol", ipProtocol).add("ports", ports); } /** @@ -341,14 +325,14 @@ public final class Firewall extends Resource { public static final class Builder { - private IPProtocol ipProtocol; + private IpProtocol ipProtocol; private RangeSet ports = TreeRangeSet.create(); /** - * @see org.jclouds.googlecomputeengine.domain.Firewall.Rule#getIPProtocol() + * @see org.jclouds.googlecomputeengine.domain.Firewall.Rule#getIpProtocol() */ - public Builder IPProtocol(IPProtocol IPProtocol) { - this.ipProtocol = IPProtocol; + public Builder IpProtocol(IpProtocol IpProtocol) { + this.ipProtocol = IpProtocol; return this; } @@ -384,7 +368,7 @@ public final class Firewall extends Resource { } public Builder fromFirewallRule(Rule firewallRule) { - return new Builder().IPProtocol(firewallRule.getIPProtocol()).ports(firewallRule.getPorts()); + return new Builder().IpProtocol(firewallRule.getIpProtocol()).ports(firewallRule.getPorts()); } } diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java index 0292c71121..24a139a8b4 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Project.java @@ -178,7 +178,7 @@ public class Project extends Resource { "metric", "usage", "limit" }) protected Quota(String metric, Double usage, Double limit) { - this.metric = checkNotNull(metric, "metric"); + this.metric = metric != null ? metric : "undefined"; this.usage = checkNotNull(usage, "usage"); this.limit = checkNotNull(limit, "limit"); } diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/internal/NetworkAndAddressRange.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/internal/NetworkAndAddressRange.java new file mode 100644 index 0000000000..66fbd6613c --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/internal/NetworkAndAddressRange.java @@ -0,0 +1,91 @@ +/* + * 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.domain.internal; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Optional.fromNullable; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.base.Objects; +import com.google.common.base.Objects.ToStringHelper; +import com.google.common.base.Optional; + +/** + * Container for network, IPv4 range and optional gateway, for creation caching + */ +public class NetworkAndAddressRange { + protected final String name; + protected final String ipV4Range; + protected final Optional gateway; + + @ConstructorProperties({ + "name", "ipV4Range", "gateway" + }) + public NetworkAndAddressRange(String name, String ipV4Range, @Nullable String gateway) { + this.name = checkNotNull(name, "name"); + this.ipV4Range = checkNotNull(ipV4Range, "ipV4Range"); + this.gateway = fromNullable(gateway); + } + + public String getName() { + return name; + } + + public String getIpV4Range() { + return ipV4Range; + } + + @Nullable + public Optional getGateway() { + return gateway; + } + + @Override + public int hashCode() { + // We only do hashcode/equals on name. + // the ip v4 range and gateway are included for creation rather than caching. + return Objects.hashCode(name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + NetworkAndAddressRange that = NetworkAndAddressRange.class.cast(obj); + return equal(this.name, that.name); + } + + protected ToStringHelper string() { + return toStringHelper(this) + .omitNullValues() + .add("name", name) + .add("ipV4Range", ipV4Range) + .add("gateway", gateway.orNull()); + } + + @Override + public String toString() { + return string().toString(); + } + + +} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeeded.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeeded.java new file mode 100644 index 0000000000..09a4eee610 --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeeded.java @@ -0,0 +1,101 @@ +/* + * 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.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL; +import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT; +import static org.jclouds.util.Predicates2.retry; + +import java.util.concurrent.atomic.AtomicReference; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.config.UserProject; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; + +/** + * @author Andrew Bayer + */ +@Singleton +public class CreateNetworkIfNeeded implements Function { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + protected final GoogleComputeEngineApi api; + protected final Supplier userProject; + private final Predicate> operationDonePredicate; + private final long operationCompleteCheckInterval; + private final long operationCompleteCheckTimeout; + + @Inject + public CreateNetworkIfNeeded(GoogleComputeEngineApi api, + @UserProject Supplier userProject, + @Named("global") Predicate> operationDonePredicate, + @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval, + @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) { + this.api = checkNotNull(api, "api"); + this.userProject = checkNotNull(userProject, "userProject"); + this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval, + "operation completed check interval"); + this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout, + "operation completed check timeout"); + this.operationDonePredicate = operationDonePredicate; + } + + @Override + public Network apply(NetworkAndAddressRange input) { + checkNotNull(input, "input"); + + try { + if (input.getGateway().isPresent()) { + AtomicReference operation = new AtomicReference(api.getNetworkApiForProject(userProject + .get()).createInIPv4RangeWithGateway(input.getName(), input.getIpV4Range(), input.getGateway().get())); + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create network, operation failed" + operation); + } else { + AtomicReference operation = new AtomicReference(api.getNetworkApiForProject(userProject + .get()).createInIPv4Range(input.getName(), input.getIpV4Range())); + retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, + MILLISECONDS).apply(operation); + + checkState(!operation.get().getHttpError().isPresent(), "Could not create network, operation failed" + operation); + } + return checkNotNull(api.getNetworkApiForProject(userProject.get()).get(input.getName()), + "no network with name %s was found", input.getName()); + } catch (IllegalStateException e) { + return api.getNetworkApiForProject(userProject.get()).get(input.getName()); + } + } +} diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java index abd2b4c02b..df96e4e318 100644 --- a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java @@ -39,7 +39,7 @@ public class GlobalOperationDonePredicate implements Predicate project; @Inject - GlobalOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier project) { + public GlobalOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier project) { this.api = api; this.project = project; } diff --git a/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java new file mode 100644 index 0000000000..e41536e232 --- /dev/null +++ b/providers/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java @@ -0,0 +1,123 @@ +/* + * 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.predicates; + +import static com.google.common.collect.Collections2.transform; + +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.googlecomputeengine.domain.Firewall.Rule; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.collect.Range; +import com.google.common.collect.Sets; + +public class NetworkFirewallPredicates { + + public static Predicate hasProtocol(final IpProtocol protocol) { + return new Predicate() { + + @Override + public boolean apply(Firewall fw) { + return Predicates.in(transform(fw.getAllowed(), new Function() { + @Override + public IpProtocol apply(Rule input) { + return input.getIpProtocol(); + } + })).apply(protocol); + + } + }; + } + + public static Predicate hasPortRange(final Range portRange) { + return new Predicate() { + + @Override + public boolean apply(Firewall fw) { + return Iterables.any(fw.getAllowed(), new Predicate() { + @Override + public boolean apply(Rule input) { + return input.getPorts().encloses(portRange); + } + }); + } + }; + } + + public static Predicate hasSourceTag(final String sourceTag) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + return input.getSourceTags() != null && input.getSourceTags().contains(sourceTag); + } + }; + } + + public static Predicate hasSourceRange(final String sourceRange) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + return input.getSourceRanges() != null && input.getSourceRanges().contains(sourceRange); + } + }; + } + + public static Predicate equalsIpPermission(final IpPermission permission) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + return Iterables.elementsEqual(permission.getGroupIds(), input.getSourceTags()) + && Iterables.elementsEqual(permission.getCidrBlocks(), input.getSourceRanges()) + && (input.getAllowed().size() == 1 + && ruleEqualsIpPermission(permission).apply(Iterables.getOnlyElement(input.getAllowed()))); + } + }; + } + + public static Predicate providesIpPermission(final IpPermission permission) { + return new Predicate() { + @Override + public boolean apply(Firewall input) { + return ((permission.getGroupIds().size() == 0 && input.getSourceTags().size() == 0) + || Sets.intersection(permission.getGroupIds(), input.getSourceTags()).size() > 0) + && ((permission.getCidrBlocks().size() == 0 && input.getSourceRanges().size() == 0) + || Sets.intersection(permission.getCidrBlocks(), input.getSourceRanges()).size() > 0) + && hasProtocol(permission.getIpProtocol()).apply(input) + && ((permission.getFromPort() == 0 && permission.getToPort() == 0) + || hasPortRange(Range.closed(permission.getFromPort(), permission.getToPort())).apply(input)); + } + }; + } + + private static Predicate ruleEqualsIpPermission(final IpPermission permission) { + return new Predicate() { + @Override + public boolean apply(Firewall.Rule input) { + return permission.getIpProtocol().equals(input.getIpProtocol()) + && ((input.getPorts().isEmpty() && permission.getFromPort() == 0 && permission.getToPort() == 0) + || (input.getPorts().asRanges().size() == 1 + && permission.getFromPort() == Iterables.getOnlyElement(input.getPorts().asRanges()).lowerEndpoint() + && permission.getToPort() == Iterables.getOnlyElement(input.getPorts().asRanges()).upperEndpoint())); + } + }; + } +} diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtensionLiveTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtensionLiveTest.java new file mode 100644 index 0000000000..6f0b4c6dc7 --- /dev/null +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtensionLiveTest.java @@ -0,0 +1,31 @@ +/* + * 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.extensions; + +import org.jclouds.compute.extensions.internal.BaseSecurityGroupExtensionLiveTest; +import org.testng.annotations.Test; + +/** + * @author Andrew Bayer + */ +@Test(groups = "live", singleThreaded = true, testName = "GoogleComputeEngineSecurityGroupExtensionLiveTest") +public class GoogleComputeEngineSecurityGroupExtensionLiveTest extends BaseSecurityGroupExtensionLiveTest { + + public GoogleComputeEngineSecurityGroupExtensionLiveTest() { + provider = "google-compute-engine"; + } +} diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermissionTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermissionTest.java new file mode 100644 index 0000000000..4970357308 --- /dev/null +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FirewallToIpPermissionTest.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.googlecomputeengine.compute.functions; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.Date; + +import org.jclouds.googlecomputeengine.domain.Firewall; +import org.jclouds.net.domain.IpPermission; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; + +public class FirewallToIpPermissionTest { + + @Test + public void testApply() { + + Firewall fw = fwForTest(); + + FirewallToIpPermission converter = new FirewallToIpPermission(); + + Iterable perms = converter.apply(fw); + + assertEquals(Iterables.size(perms), 3, "There should be three IpPermissions but there is only " + Iterables.size(perms)); + + assertTrue(Iterables.any(perms, Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(1, 10))), "No permission found for TCP, ports 1-10"); + assertTrue(Iterables.any(perms, Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(33, 33))), "No permission found for TCP, port 33"); + assertTrue(Iterables.any(perms, hasProtocol(IpProtocol.ICMP)), + "No permission found for ICMP"); + } + + public static Firewall fwForTest() { + Firewall.Builder builder = Firewall.builder(); + + builder.addSourceRange("0.0.0.0/0"); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.TCP) + .addPortRange(1, 10).build()); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.TCP) + .addPort(33).build()); + builder.addAllowed(Firewall.Rule.builder().IpProtocol(IpProtocol.ICMP).build()); + builder.id("abcd"); + builder.selfLink(URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/firewalls/jclouds-test")); + builder.network(URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/networks/jclouds-test")); + builder.creationTimestamp(new Date()); + builder.name("jclouds-test"); + + return builder.build(); + } + + public static Predicate hasProtocol(final IpProtocol protocol) { + return new Predicate() { + + @Override + public boolean apply(IpPermission perm) { + return protocol.equals(perm.getIpProtocol()); + } + }; + } + + public static Predicate hasStartAndEndPort(final int startPort, final int endPort) { + return new Predicate() { + + @Override + public boolean apply(IpPermission perm) { + return startPort == perm.getFromPort() && endPort == perm.getToPort(); + } + }; + } + +} diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java new file mode 100644 index 0000000000..79a9da09af --- /dev/null +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.googlecomputeengine.compute.functions; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermissionTest.hasProtocol; +import static org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermissionTest.hasStartAndEndPort; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.net.URI; +import java.util.Date; + +import org.jclouds.collect.IterableWithMarkers; +import org.jclouds.collect.PagedIterables; +import org.jclouds.compute.domain.SecurityGroup; +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.features.FirewallApi; +import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.googlecomputeengine.options.ListOptions.Builder; +import org.jclouds.net.domain.IpProtocol; +import org.testng.annotations.Test; + +import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +public class NetworkToSecurityGroupTest { + + @Test + public void testApply() { + Supplier projectSupplier = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + FirewallToIpPermission fwToPerm = new FirewallToIpPermission(); + + GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + FirewallApi fwApi = createMock(FirewallApi.class); + + ListOptions options = new Builder().filter("network eq .*/jclouds-test"); + expect(api.getFirewallApiForProject(projectSupplier.get())) + .andReturn(fwApi); + expect(fwApi.list(options)).andReturn(PagedIterables.of(IterableWithMarkers.from(ImmutableSet.of(FirewallToIpPermissionTest.fwForTest())))); + + replay(api, fwApi); + Network.Builder builder = Network.builder(); + + builder.id("abcd"); + builder.selfLink(URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/networks/jclouds-test")); + builder.creationTimestamp(new Date()); + builder.description("some description"); + builder.gatewayIPv4("1.2.3.4"); + builder.IPv4Range("0.0.0.0/0"); + builder.name("jclouds-test"); + + Network network = builder.build(); + + NetworkToSecurityGroup netToSg = new NetworkToSecurityGroup(fwToPerm, api, projectSupplier); + + SecurityGroup group = netToSg.apply(network); + + assertEquals(group.getId(), "jclouds-test"); + assertEquals(group.getUri(), URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/networks/jclouds-test")); + assertEquals(group.getIpPermissions().size(), 3); + assertTrue(Iterables.any(group.getIpPermissions(), Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(1, 10))), "No permission found for TCP, ports 1-10"); + assertTrue(Iterables.any(group.getIpPermissions(), Predicates.and(hasProtocol(IpProtocol.TCP), + hasStartAndEndPort(33, 33))), "No permission found for TCP, port 33"); + assertTrue(Iterables.any(group.getIpPermissions(), hasProtocol(IpProtocol.ICMP)), + "No permission found for ICMP"); + } +} diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreateTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreateTest.java new file mode 100644 index 0000000000..af384a5733 --- /dev/null +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/loaders/FindNetworkOrCreateTest.java @@ -0,0 +1,144 @@ +/* + * 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.loaders; + +import static com.google.common.base.Optional.fromNullable; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.features.GlobalOperationApi; +import org.jclouds.googlecomputeengine.features.NetworkApi; +import org.jclouds.googlecomputeengine.functions.CreateNetworkIfNeeded; +import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; + +/** + * @author Andrew Bayer + */ +public class FindNetworkOrCreateTest { + + @Test + public void testLoadExisting() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network") + .selfLink(URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/networks/this-network")) + .build(); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + + expect(nwApi.get("this-network")).andReturn(network); + + replay(api, nwApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", null); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, userProject); + + LoadingCache cache = CacheBuilder.newBuilder().build(loader); + + assertEquals(cache.getUnchecked(input), network); + + // Second call is to ensure we only need to make the API calls once. + assertEquals(cache.getUnchecked(input), network); + + verify(api, nwApi); + } + + @Test + public void testLoadNew() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + final GlobalOperationApi globalApi = createMock(GlobalOperationApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network") + .selfLink(URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/networks/this-network")) + .build(); + + Operation createOp = createMock(Operation.class); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + expect(api.getGlobalOperationApiForProject(userProject.get())).andReturn(globalApi).atLeastOnce(); + + expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")) + .andReturn(createOp); + expect(globalApi.get("create-op")).andReturn(createOp); + // pre-creation + expect(nwApi.get("this-network")).andReturn(null); + // post-creation + expect(nwApi.get("this-network")).andReturn(network); + + expect(createOp.getName()).andReturn("create-op"); + expect(createOp.getStatus()).andReturn(Operation.Status.DONE); + expect(createOp.getHttpError()).andReturn(fromNullable((HttpResponse)null)); + replay(api, nwApi, createOp, globalApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", null); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, userProject); + + LoadingCache cache = CacheBuilder.newBuilder().build(loader); + + assertEquals(cache.getUnchecked(input), network); + + // Second call is to ensure we only need to make the API calls once. + assertEquals(cache.getUnchecked(input), network); + + verify(api, nwApi, globalApi, createOp); + + } +} + diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java index 6345c51000..6a20d28d83 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiExpectTest.java @@ -21,7 +21,6 @@ import static com.google.common.collect.Iterables.transform; import static java.lang.String.format; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE; import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE; -import static org.jclouds.googlecomputeengine.domain.Firewall.Rule.IPProtocol; import static org.jclouds.io.Payloads.newStringPayload; import static org.jclouds.util.Strings2.toStringAndClose; import static org.testng.Assert.assertEquals; @@ -43,6 +42,7 @@ import org.jclouds.googlecomputeengine.parse.ParseOperationTest; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.jclouds.io.Payload; +import org.jclouds.net.domain.IpProtocol; import org.testng.annotations.Test; import com.google.common.base.Function; @@ -147,7 +147,7 @@ public class FirewallApiExpectTest extends BaseGoogleComputeEngineApiExpectTest ".com/compute/v1beta15/projects/myproject/global/networks/default"), new FirewallOptions() .addAllowedRule(Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(22) .addPortRange(23, 24).build()) .addSourceTag("tag1") @@ -185,7 +185,7 @@ public class FirewallApiExpectTest extends BaseGoogleComputeEngineApiExpectTest .network(URI.create("https://www.googleapis" + ".com/compute/v1beta15/projects/myproject/global/networks/default")) .addAllowedRule(Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(22) .addPortRange(23, 24).build()) .addSourceTag("tag1") @@ -222,7 +222,7 @@ public class FirewallApiExpectTest extends BaseGoogleComputeEngineApiExpectTest .network(URI.create("https://www.googleapis" + ".com/compute/v1beta15/projects/myproject/global/networks/default")) .addAllowedRule(Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(22) .addPortRange(23, 24).build()) .addSourceTag("tag1") diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java index 8c550b7c08..ca188832da 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java @@ -17,7 +17,6 @@ package org.jclouds.googlecomputeengine.features; import static com.google.common.collect.Iterables.getOnlyElement; -import static org.jclouds.googlecomputeengine.domain.Firewall.Rule.IPProtocol; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -28,6 +27,7 @@ import org.jclouds.googlecomputeengine.domain.Firewall; import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest; import org.jclouds.googlecomputeengine.options.FirewallOptions; import org.jclouds.googlecomputeengine.options.ListOptions; +import org.jclouds.net.domain.IpProtocol; import org.testng.annotations.Test; import com.google.common.collect.ImmutableSet; @@ -57,7 +57,7 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { FirewallOptions firewall = new FirewallOptions() .addAllowedRule( Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(22).build()) .addSourceRange("10.0.0.0/8") .addSourceTag("tag1") @@ -79,7 +79,7 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { .addTargetTag("tag2") .allowedRules(ImmutableSet.of( Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(23) .build())); @@ -96,11 +96,11 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME)) .allowedRules(ImmutableSet.of( Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(22) .build(), Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(23) .build())) .addSourceRange("10.0.0.0/8") @@ -119,11 +119,11 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest { .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME)) .allowedRules(ImmutableSet.of( Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(22) .build(), Firewall.Rule.builder() - .IPProtocol(IPProtocol.TCP) + .IpProtocol(IpProtocol.TCP) .addPort(23) .build())) .addSourceRange("10.0.0.0/8") diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeededTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeededTest.java new file mode 100644 index 0000000000..4bbff5e780 --- /dev/null +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/functions/CreateNetworkIfNeededTest.java @@ -0,0 +1,133 @@ +/* + * 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.functions; + +import static com.google.common.base.Optional.fromNullable; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.jclouds.googlecomputeengine.GoogleComputeEngineApi; +import org.jclouds.googlecomputeengine.domain.Network; +import org.jclouds.googlecomputeengine.domain.Operation; +import org.jclouds.googlecomputeengine.domain.internal.NetworkAndAddressRange; +import org.jclouds.googlecomputeengine.features.GlobalOperationApi; +import org.jclouds.googlecomputeengine.features.NetworkApi; +import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; + +/** + * @author Andrew Bayer + */ +public class CreateNetworkIfNeededTest { + + @Test + public void testApply() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + final GlobalOperationApi globalApi = createMock(GlobalOperationApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network") + .selfLink(URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/networks/this-network")) + .build(); + + Operation createOp = createMock(Operation.class); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + expect(api.getGlobalOperationApiForProject(userProject.get())).andReturn(globalApi).atLeastOnce(); + + expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")) + .andReturn(createOp); + expect(globalApi.get("create-op")).andReturn(createOp); + expect(nwApi.get("this-network")).andReturn(network); + + expect(createOp.getName()).andReturn("create-op"); + expect(createOp.getStatus()).andReturn(Operation.Status.DONE); + expect(createOp.getHttpError()).andReturn(fromNullable((HttpResponse)null)); + replay(api, nwApi, createOp, globalApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", null); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + assertEquals(creator.apply(input), network); + + verify(api, nwApi, globalApi, createOp); + } + + @Test + public void testApplyWithGateway() { + final GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class); + final NetworkApi nwApi = createMock(NetworkApi.class); + final GlobalOperationApi globalApi = createMock(GlobalOperationApi.class); + + Network network = Network.builder().IPv4Range("0.0.0.0/0") + .id("abcd").name("this-network").gatewayIPv4("1.2.3.4") + .selfLink(URI.create("https://www.googleapis.com/compute/v1beta15/projects/myproject/global/networks/this-network")) + .build(); + + Operation createOp = createMock(Operation.class); + + final Supplier userProject = new Supplier() { + @Override + public String get() { + return "myproject"; + } + }; + + expect(api.getNetworkApiForProject(userProject.get())).andReturn(nwApi).atLeastOnce(); + expect(api.getGlobalOperationApiForProject(userProject.get())).andReturn(globalApi).atLeastOnce(); + + expect(nwApi.createInIPv4RangeWithGateway("this-network", "0.0.0.0/0", "1.2.3.4")) + .andReturn(createOp); + expect(globalApi.get("create-op")).andReturn(createOp); + expect(nwApi.get("this-network")).andReturn(network); + + expect(createOp.getName()).andReturn("create-op"); + expect(createOp.getStatus()).andReturn(Operation.Status.DONE); + expect(createOp.getHttpError()).andReturn(fromNullable((HttpResponse)null)); + replay(api, nwApi, createOp, globalApi); + + NetworkAndAddressRange input = new NetworkAndAddressRange("this-network", "0.0.0.0/0", "1.2.3.4"); + + GlobalOperationDonePredicate pred = new GlobalOperationDonePredicate(api, userProject); + + CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l); + + assertEquals(creator.apply(input), network); + + verify(api, nwApi, globalApi, createOp); + } + +} diff --git a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.java b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.java index a90f17bfc1..1bbf753e81 100644 --- a/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.java +++ b/providers/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseFirewallListTest.java @@ -26,6 +26,7 @@ import org.jclouds.googlecomputeengine.domain.Firewall; import org.jclouds.googlecomputeengine.domain.ListPage; import org.jclouds.googlecomputeengine.domain.Resource; import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineParseTest; +import org.jclouds.net.domain.IpProtocol; import org.testng.annotations.Test; import com.google.common.collect.ImmutableSet; @@ -61,7 +62,7 @@ public class ParseFirewallListTest extends BaseGoogleComputeEngineParseTest