From 67924f188e9b82d196feade209625bad69fa05e9 Mon Sep 17 00:00:00 2001 From: David Ribeiro Alves Date: Tue, 15 Jan 2013 11:20:03 -0600 Subject: [PATCH] gce - firewalls api --- .../googlecompute/GoogleComputeApi.java | 10 + .../googlecompute/GoogleComputeAsyncApi.java | 11 + .../config/GoogleComputeParserModule.java | 58 ++- .../config/GoogleComputeRestClientModule.java | 3 + .../googlecompute/domain/Firewall.java | 394 ++++++++++++++++++ .../googlecompute/features/FirewallApi.java | 126 ++++++ .../features/FirewallAsyncApi.java | 180 ++++++++ .../functions/internal/PATCH.java | 38 ++ .../functions/internal/ParseFirewalls.java | 68 +++ .../features/FirewallApiExpectTest.java | 244 +++++++++++ .../features/FirewallApiLiveTest.java | 153 +++++++ .../parse/ParseFirewallListTest.java | 71 ++++ .../parse/ParseFirewallTest.java | 67 +++ .../src/test/resources/firewall_get.json | 30 ++ .../src/test/resources/firewall_insert.json | 1 + .../src/test/resources/firewall_list.json | 58 +++ 16 files changed, 1505 insertions(+), 7 deletions(-) create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Firewall.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallApi.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallAsyncApi.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/PATCH.java create mode 100644 labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseFirewalls.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiExpectTest.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiLiveTest.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallListTest.java create mode 100644 labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallTest.java create mode 100644 labs/google-compute/src/test/resources/firewall_get.json create mode 100644 labs/google-compute/src/test/resources/firewall_insert.json create mode 100644 labs/google-compute/src/test/resources/firewall_list.json diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java index f9f05cc8f7..93153d8d12 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeApi.java @@ -20,6 +20,7 @@ package org.jclouds.googlecompute; import com.google.common.annotations.Beta; import org.jclouds.googlecompute.features.DiskApi; +import org.jclouds.googlecompute.features.FirewallApi; import org.jclouds.googlecompute.features.KernelApi; import org.jclouds.googlecompute.features.MachineTypeApi; import org.jclouds.googlecompute.features.NetworkApi; @@ -51,6 +52,15 @@ public interface GoogleComputeApi { @Path("/projects/{project}") DiskApi getDiskApiForProject(@PathParam("project") String projectName); + /** + * Provides synchronous access to Firewall features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + FirewallApi getFirewallApiForProject(@PathParam("project") String projectName); + /** * Provides synchronous access to Kernel features * diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java index a11bea8c9b..39fb0d7513 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/GoogleComputeAsyncApi.java @@ -20,6 +20,7 @@ package org.jclouds.googlecompute; import com.google.common.annotations.Beta; import org.jclouds.googlecompute.features.DiskAsyncApi; +import org.jclouds.googlecompute.features.FirewallAsyncApi; import org.jclouds.googlecompute.features.KernelAsyncApi; import org.jclouds.googlecompute.features.MachineTypeAsyncApi; import org.jclouds.googlecompute.features.NetworkAsyncApi; @@ -31,6 +32,7 @@ import org.jclouds.rest.annotations.Delegate; import javax.ws.rs.Path; import javax.ws.rs.PathParam; + /** * Provides asynchronous access to GoogleCompute via their REST API. *

@@ -50,6 +52,15 @@ public interface GoogleComputeAsyncApi { @Path("/projects/{project}") DiskAsyncApi getDiskApiForProject(@PathParam("project") String projectName); + /** + * Provides asynchronous access to Firewall features + * + * @param projectName the name of the project + */ + @Delegate + @Path("/projects/{project}") + FirewallAsyncApi getFirewallApiForProject(@PathParam("project") String projectName); + /** * Provides asynchronous access to Kernel features * diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java index ff9abc8119..c98365725d 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeParserModule.java @@ -21,6 +21,7 @@ package org.jclouds.googlecompute.config; import com.google.common.collect.ForwardingMap; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Range; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; @@ -32,6 +33,7 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.inject.AbstractModule; import com.google.inject.Provides; +import org.jclouds.googlecompute.domain.Firewall; import org.jclouds.googlecompute.domain.Operation; import org.jclouds.googlecompute.domain.Project; import org.jclouds.json.config.GsonModule; @@ -48,6 +50,8 @@ import java.util.Date; import java.util.Map; import java.util.Set; +import static org.jclouds.googlecompute.domain.Firewall.Rule; + /** * @author David Alves */ @@ -61,13 +65,14 @@ public class GoogleComputeParserModule extends AbstractModule { @Provides @Singleton public Map provideCustomAdapterBindings() { - return ImmutableMap.of( - Metadata.class, new MetadataTypeAdapter(), - Operation.class, new OperationTypeAdapter(), - Header.class, new HeaderTypeAdapter(), - ClaimSet.class, new ClaimSetTypeAdapter(), - Project.class, new ProjectTypeAdapter() - ); + return new ImmutableMap.Builder() + .put(Metadata.class, new MetadataTypeAdapter()) + .put(Operation.class, new OperationTypeAdapter()) + .put(Header.class, new HeaderTypeAdapter()) + .put(ClaimSet.class, new ClaimSetTypeAdapter()) + .put(Project.class, new ProjectTypeAdapter()) + .put(Rule.class, new RuleTypeAdapter()) + .build(); } /** @@ -188,4 +193,43 @@ public class GoogleComputeParserModule extends AbstractModule { } } + + private static class RuleTypeAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public Firewall.Rule deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + JsonObject rule = json.getAsJsonObject(); + Rule.Builder builder = Rule.builder(); + builder.IPProtocol(Rule.IPProtocol.fromValue(rule.get("IPProtocol").getAsString())); + if (rule.get("ports") != null) { + JsonArray ports = (JsonArray) rule.get("ports"); + for (JsonElement port : ports) { + String portAsString = port.getAsString(); + if (portAsString.contains("-")) { + String[] split = portAsString.split("-"); + builder.addPortRange(Integer.parseInt(split[0]), Integer.parseInt(split[1])); + } else { + builder.addPort(Integer.parseInt(portAsString)); + } + } + } + return builder.build(); + } + + @Override + public JsonElement serialize(Firewall.Rule src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject ruleObject = new JsonObject(); + ruleObject.addProperty("IPProtocol", src.getIPProtocol().value()); + if (src.getPorts() != null && !src.getPorts().isEmpty()) { + JsonArray ports = new JsonArray(); + for (Range range : src.getPorts().asRanges()) { + ports.add(new JsonPrimitive(range.lowerEndpoint() == range.upperEndpoint() ? range.lowerEndpoint() + "" : + range.lowerEndpoint() + "-" + range.upperEndpoint())); + } + ruleObject.add("ports", ports); + } + return ruleObject; + } + } } diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java index e7f3213baa..0afa8109b9 100644 --- a/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/config/GoogleComputeRestClientModule.java @@ -29,6 +29,8 @@ import org.jclouds.googlecompute.GoogleComputeAsyncApi; import org.jclouds.googlecompute.domain.Operation; import org.jclouds.googlecompute.features.DiskApi; import org.jclouds.googlecompute.features.DiskAsyncApi; +import org.jclouds.googlecompute.features.FirewallApi; +import org.jclouds.googlecompute.features.FirewallAsyncApi; import org.jclouds.googlecompute.features.KernelApi; import org.jclouds.googlecompute.features.KernelAsyncApi; import org.jclouds.googlecompute.features.MachineTypeApi; @@ -67,6 +69,7 @@ import static com.google.common.base.Preconditions.checkState; public class GoogleComputeRestClientModule extends RestClientModule { public static final Map, Class> DELEGATE_MAP = ImmutableMap., Class>builder() .put(DiskApi.class, DiskAsyncApi.class) + .put(FirewallApi.class, FirewallAsyncApi.class) .put(KernelApi.class, KernelAsyncApi.class) .put(MachineTypeApi.class, MachineTypeAsyncApi.class) .put(NetworkApi.class, NetworkAsyncApi.class) diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Firewall.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Firewall.java new file mode 100644 index 0000000000..860a87ebe0 --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/domain/Firewall.java @@ -0,0 +1,394 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.domain; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.RangeSet; +import com.google.common.collect.TreeRangeSet; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Date; +import java.util.Set; + +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 static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Range.closed; +import static com.google.common.collect.Range.singleton; + +/** + * Represents a network firewall + * + * @author David Alves + * @see + * @see + */ +@Beta +public final class Firewall extends Resource { + + private final URI network; + private final Set sourceRanges; + private final Set sourceTags; + private final Set targetTags; + private final Set allowed; + + @ConstructorProperties({ + "id", "creationTimestamp", "selfLink", "name", "description", "network", "sourceRanges", + "sourceTags", "targetTags", "allowed" + }) + protected Firewall(String id, Date creationTimestamp, URI selfLink, String name, String description, + URI network, Set sourceRanges, Set sourceTags, Set targetTags, + Set allowed) { + super(Kind.FIREWALL, id, fromNullable(creationTimestamp), selfLink, checkNotNull(name, "name"), + fromNullable(description)); + this.network = checkNotNull(network, "network of %s", name); + this.sourceRanges = sourceRanges == null ? ImmutableSet.of() : sourceRanges; + this.sourceTags = sourceTags == null ? ImmutableSet.of() : sourceTags; + this.targetTags = targetTags == null ? ImmutableSet.of() : targetTags; + this.allowed = allowed == null ? ImmutableSet.of() : allowed; + } + + /** + * @return URI of the network to which this firewall is applied; provided by the client when the firewall is created. + */ + public URI getNetwork() { + return network; + } + + /** + * One or both of sourceRanges and sourceTags may be set; an inbound connection is allowed if either the range or + * the tag of the source matches. + * + * @return a list of IP address blocks expressed in CIDR format which this rule applies to. + */ + public Set getSourceRanges() { + return sourceRanges; + } + + /** + * @return a list of instance tags which this rule applies to. One or both of sourceRanges and sourceTags may be + * set; an inbound connection is allowed if either the range or the tag of the source matches. + */ + public Set getSourceTags() { + return sourceTags; + } + + /** + * If no targetTags are specified, the firewall rule applies to all instances on the specified network. + * + * @return a list of instance tags indicating sets of instances located on network which may make network + * connections as specified in allowed. + */ + public Set getTargetTags() { + return targetTags; + } + + /** + * Each rule specifies a protocol and port-range tuple that describes a permitted connection. + * + * @return the list of rules specified by this firewall. + */ + public Set getAllowed() { + return allowed; + } + + /** + * {@inheritDoc} + */ + protected Objects.ToStringHelper string() { + return super.string() + .add("network", network).add("sourceRanges", sourceRanges).add("sourceTags", + sourceTags).add("targetTags", targetTags).add("allowed", allowed); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromFirewall(this); + } + + public static final class Builder extends Resource.Builder { + + private URI network; + private ImmutableSet.Builder sourceRanges = ImmutableSet.builder(); + private ImmutableSet.Builder sourceTags = ImmutableSet.builder(); + private ImmutableSet.Builder targetTags = ImmutableSet.builder(); + private ImmutableSet.Builder allowed = ImmutableSet.builder(); + + /** + * @see Firewall#getNetwork() + */ + public Builder network(URI network) { + this.network = network; + return this; + } + + /** + * @see Firewall#getSourceRanges() + */ + public Builder addSourceRange(String sourceRange) { + this.sourceRanges.add(checkNotNull(sourceRange)); + return this; + } + + /** + * @see Firewall#getSourceRanges() + */ + public Builder sourceRanges(Set sourceRanges) { + this.sourceRanges.addAll(checkNotNull(sourceRanges)); + return this; + } + + /** + * @see Firewall#getSourceTags() + */ + public Builder addSourceTag(String sourceTag) { + this.sourceTags.add(checkNotNull(sourceTag)); + return this; + } + + /** + * @see Firewall#getSourceTags() + */ + public Builder sourceTags(Set sourceTags) { + this.sourceTags.addAll(checkNotNull(sourceTags)); + return this; + } + + /** + * @see Firewall#getTargetTags() + */ + public Builder addTargetTag(String targetTag) { + this.targetTags.add(checkNotNull(targetTag)); + return this; + } + + /** + * @see Firewall#getTargetTags() + */ + public Builder targetTags(Set targetTags) { + this.targetTags.addAll(checkNotNull(targetTags)); + return this; + } + + /** + * @see Firewall#getAllowed() + */ + public Builder addAllowed(Rule firewallRule) { + this.allowed.add(checkNotNull(firewallRule)); + return this; + } + + /** + * @see Firewall#getAllowed() + */ + public Builder allowed(Set firewallRules) { + this.allowed = ImmutableSet.builder(); + this.allowed.addAll(firewallRules); + return this; + } + + @Override + protected Builder self() { + return this; + } + + public Firewall build() { + return new Firewall(super.id, super.creationTimestamp, super.selfLink, super.name, + super.description, network, sourceRanges.build(), sourceTags.build(), targetTags.build(), + allowed.build()); + } + + public Builder fromFirewall(Firewall in) { + return super.fromResource(in).network(in.getNetwork()).sourceRanges(in.getSourceRanges()).sourceTags(in + .getSourceTags()).targetTags(in.getTargetTags()).allowed(in.getAllowed()); + } + + } + + /** + * A Firewall rule. Rule specifies a protocol and port-range tuple that describes a + * permitted connection. + * + * @author David Alves + * @see + */ + 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 RangeSet ports; + + @ConstructorProperties({ + "IPProtocol", "ports" + }) + private Rule(IPProtocol IPProtocol, RangeSet ports) { + this.ipProtocol = checkNotNull(IPProtocol); + this.ports = ports == null ? TreeRangeSet.create() : ports; + } + + /** + * This can either be a well known protocol string (tcp, udp or icmp) or the IP protocol number. + * + * @return this is the IP protocol that is allowed for this rule. + */ + public IPProtocol getIPProtocol() { + return ipProtocol; + } + + /** + * Each entry must be either an integer or a range. If not specified, connections through any port are allowed. + * Example inputs include: ["22"], ["80,"443"], and ["12345-12349"]. + *

+ * It is an error to specify this for any protocol that isn't UDP or TCP. + * + * @return An optional list of ports which are allowed. + */ + public RangeSet getPorts() { + return ports; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return Objects.hashCode(ipProtocol, ports); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Rule that = Rule.class.cast(obj); + return equal(this.ipProtocol, that.ipProtocol) + && equal(this.ports, that.ports); + } + + /** + * {@inheritDoc} + */ + public Objects.ToStringHelper string() { + return toStringHelper(this) + .add("IPProtocol", ipProtocol).add("ports", ports); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return string().toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromFirewallRule(this); + } + + public static final class Builder { + + private IPProtocol ipProtocol; + private RangeSet ports = TreeRangeSet.create(); + + /** + * @see org.jclouds.googlecompute.domain.Firewall.Rule#getIPProtocol() + */ + public Builder IPProtocol(IPProtocol IPProtocol) { + this.ipProtocol = checkNotNull(IPProtocol); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Firewall.Rule#getPorts() + */ + public Builder addPort(Integer port) { + this.ports.add(singleton(checkNotNull(port, "port"))); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Firewall.Rule#getPorts() + */ + public Builder addPortRange(Integer start, Integer end) { + checkState(checkNotNull(start, "start") < checkNotNull(end, "end"), + "start of range must be lower than end of range"); + this.ports.add(closed(start, end)); + return this; + } + + /** + * @see org.jclouds.googlecompute.domain.Firewall.Rule#getPorts() + */ + public Builder ports(RangeSet ports) { + this.ports = TreeRangeSet.create(); + this.ports.addAll(ports); + return this; + } + + public Rule build() { + return new Rule(ipProtocol, ports); + } + + public Builder fromFirewallRule(Rule firewallRule) { + return new Builder().IPProtocol(firewallRule.getIPProtocol()).ports(firewallRule.getPorts()); + } + } + + } +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallApi.java new file mode 100644 index 0000000000..54b27bd095 --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallApi.java @@ -0,0 +1,126 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.domain.Operation; +import org.jclouds.googlecompute.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; + +/** + * Provides synchronous access to Firewalls via their REST API. + *

+ * TODO support PATCH + * (GCE uses PATCH as a Http method. Using this method is the only way to partially update a firewall.) + * + * @author David Alves + * @see FirewallAsyncApi + * @see + */ +public interface FirewallApi { + + /** + * Returns the specified image resource. + * + * @param firewallName name of the firewall resource to return. + * @return an Firewall resource + */ + Firewall get(String firewallName); + + /** + * Creates a firewall resource in the specified project using the data included in the request. + * + * + * @param firewall the firewall to be inserted. + * @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. + */ + Operation create(Firewall firewall); + + /** + * Updates the specified firewall resource with the data included in the request. + * + * @param firewallName the name firewall to be updated. + * @param firewall the new firewall. + * @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. + */ + Operation update(String firewallName, Firewall firewall); + + /** + * Updates the specified firewall resource, with patch semantics, with the data included in the request. + * + * @param firewallName the name firewall to be updated. + * @param firewall the new firewall. + * @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. + */ + Operation patch(String firewallName, Firewall firewall); + + /** + * Deletes the specified image resource. + * + * @param imageName name of the firewall resource to delete. + * @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. If the image did not exist the result is null. + */ + Operation delete(String imageName); + + /** + * @see FirewallApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + ListPage listFirstPage(); + + /** + * @see FirewallApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + ListPage listAtMarker(@Nullable String marker); + + /** + * Retrieves the list of firewall resources available to the specified project. + * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not + * been set. + * + * @param marker marks the beginning of the next list page + * @param listOptions listing options + * @return a page of the list + * @see ListOptions + * @see org.jclouds.googlecompute.domain.ListPage + */ + ListPage listAtMarker(@Nullable String marker, @Nullable ListOptions listOptions); + + /** + * @see FirewallApi#list(org.jclouds.googlecompute.options.ListOptions) + */ + public PagedIterable list(); + + /** + * A paged version of FirewallApi#list() + * + * @return a Paged, Fluent Iterable that is able to fetch additional pages when required + * @see PagedIterable + * @see FirewallApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + PagedIterable list(@Nullable ListOptions listOptions); + + +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallAsyncApi.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallAsyncApi.java new file mode 100644 index 0000000000..eb2032613f --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/features/FirewallAsyncApi.java @@ -0,0 +1,180 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import com.google.common.util.concurrent.ListenableFuture; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.domain.Operation; +import org.jclouds.googlecompute.functions.internal.PATCH; +import org.jclouds.googlecompute.functions.internal.ParseFirewalls; +import org.jclouds.googlecompute.options.ListOptions; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.oauth.v2.config.OAuthScopes; +import org.jclouds.oauth.v2.filters.OAuthAuthenticator; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SkipEncoding; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.binders.BindToJsonPayload; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import static org.jclouds.Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404; +import static org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import static org.jclouds.Fallbacks.NullOnNotFoundOr404; +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_SCOPE; + +/** + * Provides asynchronous access to Firewalls via their REST API. + * + * @author David Alves + * @see FirewallApi + *

+ * Note: Patch is unsupported, jclouds side, at the moment + */ +@SkipEncoding({'/', '='}) +@RequestFilters(OAuthAuthenticator.class) +public interface FirewallAsyncApi { + + /** + * @see FirewallApi#get(String) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/firewalls/{firewall}") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + ListenableFuture get(@PathParam("firewall") String firewallName); + + /** + * @see FirewallApi#create(org.jclouds.googlecompute.domain.Firewall) + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/firewalls") + @OAuthScopes({COMPUTE_SCOPE}) + ListenableFuture create(@BinderParam(BindToJsonPayload.class) Firewall firewall); + + /** + * @see FirewallApi#update(String, org.jclouds.googlecompute.domain.Firewall) + */ + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/firewalls/{firewall}") + @OAuthScopes({COMPUTE_SCOPE}) + ListenableFuture update(@PathParam("firewall") String firewallName, + @BinderParam(BindToJsonPayload.class) Firewall firewall); + + /** + * @see FirewallApi#patch(String, org.jclouds.googlecompute.domain.Firewall) + */ + @PATCH + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/firewalls/{firewall}") + @OAuthScopes({COMPUTE_SCOPE}) + ListenableFuture patch(@PathParam("firewall") String firewallName, + @BinderParam(BindToJsonPayload.class) Firewall firewall); + + /** + * @see FirewallApi#delete(String) + */ + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Path("/firewalls/{firewall}") + @OAuthScopes(COMPUTE_SCOPE) + @Fallback(NullOnNotFoundOr404.class) + ListenableFuture delete(@PathParam("firewall") String firewallName); + + /** + * @see FirewallApi#listFirstPage() + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListenableFuture> listFirstPage(); + + /** + * @see FirewallApi#listAtMarker(String) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListenableFuture> listAtMarker(@QueryParam("pageToken") @Nullable String marker); + + /** + * @see FirewallApi#listAtMarker(String, org.jclouds.googlecompute.options.ListOptions) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Fallback(EmptyIterableWithMarkerOnNotFoundOr404.class) + ListenableFuture> listAtMarker(@QueryParam("pageToken") @Nullable String marker, + ListOptions options); + + /** + * @see FirewallApi#list() + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Transform(ParseFirewalls.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + ListenableFuture> list(); + + + /** + * @see FirewallApi#list(org.jclouds.googlecompute.options.ListOptions) + */ + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Path("/firewalls") + @OAuthScopes(COMPUTE_READONLY_SCOPE) + @ResponseParser(ParseFirewalls.class) + @Transform(ParseFirewalls.ToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + ListenableFuture> list(ListOptions options); +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/PATCH.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/PATCH.java new file mode 100644 index 0000000000..c638377c9c --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/PATCH.java @@ -0,0 +1,38 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.functions.internal; + +import javax.ws.rs.HttpMethod; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that the annotated method responds to HTTP PATCH requests + * + * @author David Alves + * @see javax.ws.rs.HttpMethod + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@HttpMethod("PATCH") +public @interface PATCH { +} diff --git a/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseFirewalls.java b/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseFirewalls.java new file mode 100644 index 0000000000..4568c5555f --- /dev/null +++ b/labs/google-compute/src/main/java/org/jclouds/googlecompute/functions/internal/ParseFirewalls.java @@ -0,0 +1,68 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.functions.internal; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.googlecompute.GoogleComputeApi; +import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.options.ListOptions; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; + +import javax.inject.Inject; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author David Alves + */ +public class ParseFirewalls extends ParseJson> { + + @Inject + public ParseFirewalls(Json json) { + super(json, new TypeLiteral>() {}); + } + + public static class ToPagedIterable extends BaseToPagedIterable { + + private final GoogleComputeApi api; + + @Inject + protected ToPagedIterable(GoogleComputeApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> fetchNextPage(final String projectName, + final String marker, + final ListOptions options) { + return new Function>() { + + @Override + public IterableWithMarker apply(Object input) { + return api.getFirewallApiForProject(projectName).listAtMarker(marker, options); + } + }; + } + } +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiExpectTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiExpectTest.java new file mode 100644 index 0000000000..50e23efc91 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiExpectTest.java @@ -0,0 +1,244 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiExpectTest; +import org.jclouds.googlecompute.parse.ParseFirewallListTest; +import org.jclouds.googlecompute.parse.ParseFirewallTest; +import org.jclouds.googlecompute.parse.ParseOperationTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +import javax.ws.rs.core.MediaType; +import java.net.URI; + +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_READONLY_SCOPE; +import static org.jclouds.googlecompute.GoogleComputeConstants.COMPUTE_SCOPE; +import static org.jclouds.googlecompute.domain.Firewall.Rule.IPProtocol; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertNull; + +/** + * @author David Alves + */ +@Test(groups = "unit") +public class FirewallApiExpectTest extends BaseGoogleComputeApiExpectTest { + + public void testGetFirewallResponseIs2xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/google/firewalls/default-allow-internal") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/firewall_get.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getFirewallApiForProject("google"); + + assertEquals(api.get("default-allow-internal"), + new ParseFirewallTest().expected()); + } + + public void testGetFirewallResponseIs4xx() throws Exception { + HttpRequest get = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/google/firewalls/default-allow-internal") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, get, operationResponse).getFirewallApiForProject("google"); + + assertNull(api.get("default-allow-internal")); + } + + public void testInsertFirewallResponseIs2xx() { + HttpRequest insert = HttpRequest + .builder() + .method("POST") + .endpoint("https://www.googleapis.com/compute/v1beta13/projects/myproject/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/firewall_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse insertFirewallResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, insert, + insertFirewallResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.create(Firewall.builder() + .name("myfw") + .network(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default")) + .addAllowed(Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(22) + .addPortRange(23, 24).build()) + .addSourceTag("tag1") + .addSourceRange("10.0.1.0/32") + .addTargetTag("tag2") + .build()), new ParseOperationTest().expected()); + } + + public void testUpdateFirewallResponseIs2xx() { + HttpRequest update = HttpRequest + .builder() + .method("PUT") + .endpoint("https://www.googleapis.com/compute/v1beta13/projects/myproject/firewalls/myfw") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/firewall_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse updateFirewallResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, update, + updateFirewallResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.update("myfw", Firewall.builder() + .name("myfw") + .network(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default")) + .addAllowed(Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(22) + .addPortRange(23, 24).build()) + .addSourceTag("tag1") + .addSourceRange("10.0.1.0/32") + .addTargetTag("tag2") + .build()), new ParseOperationTest().expected()); + } + + public void testPatchFirewallResponseIs2xx() { + HttpRequest update = HttpRequest + .builder() + .method("PATCH") + .endpoint("https://www.googleapis.com/compute/v1beta13/projects/myproject/firewalls/myfw") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN) + .payload(payloadFromResourceWithContentType("/firewall_insert.json", MediaType.APPLICATION_JSON)) + .build(); + + HttpResponse updateFirewallResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, update, + updateFirewallResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.patch("myfw", Firewall.builder() + .name("myfw") + .network(URI.create("https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default")) + .addAllowed(Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(22) + .addPortRange(23, 24).build()) + .addSourceTag("tag1") + .addSourceRange("10.0.1.0/32") + .addTargetTag("tag2") + .build()), new ParseOperationTest().expected()); + } + + public void testDeleteFirewallResponseIs2xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/firewalls/default-allow-internal") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/operation.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.delete("default-allow-internal"), + new ParseOperationTest().expected()); + } + + public void testDeleteFirewallResponseIs4xx() { + HttpRequest delete = HttpRequest + .builder() + .method("DELETE") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/firewalls/default-allow-internal") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), + TOKEN_RESPONSE, delete, deleteResponse).getFirewallApiForProject("myproject"); + + assertNull(api.delete("default-allow-internal")); + } + + public void testListFirewallsResponseIs2xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResource("/firewall_list.json")).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getFirewallApiForProject("myproject"); + + assertEquals(api.listFirstPage().toString(), + new ParseFirewallListTest().expected().toString()); + } + + public void testListFirewallsResponseIs4xx() { + HttpRequest list = HttpRequest + .builder() + .method("GET") + .endpoint("https://www.googleapis" + + ".com/compute/v1beta13/projects/myproject/firewalls") + .addHeader("Accept", "application/json") + .addHeader("Authorization", "Bearer " + TOKEN).build(); + + HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build(); + + FirewallApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE), + TOKEN_RESPONSE, list, operationResponse).getFirewallApiForProject("myproject"); + + assertTrue(api.list().concat().isEmpty()); + } +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiLiveTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiLiveTest.java new file mode 100644 index 0000000000..d9c1f391b7 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/features/FirewallApiLiveTest.java @@ -0,0 +1,153 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.features; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import org.jclouds.collect.PagedIterable; +import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.internal.BaseGoogleComputeApiLiveTest; +import org.jclouds.googlecompute.options.ListOptions; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.List; + +import static com.google.common.collect.Iterables.getOnlyElement; +import static org.jclouds.googlecompute.domain.Firewall.Rule.IPProtocol; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + * @author David Alves + */ +public class FirewallApiLiveTest extends BaseGoogleComputeApiLiveTest { + + private static final String FIREWALL_NAME = "firewall-api-live-test-firewall"; + private static final int TIME_WAIT = 30; + + private Firewall firewall; + + @BeforeClass(groups = {"integration", "live"}) + public void setupContext() { + super.setupContext(); + firewall = Firewall.builder() + .name(FIREWALL_NAME) + .network(getDefaultNetworkUrl(getUserProject())) + .addAllowed( + Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(22).build()) + .addSourceRange("10.0.0.0/8") + .addSourceTag("tag1") + .addTargetTag("tag2") + .build(); + } + + private FirewallApi api() { + return context.getApi().getFirewallApiForProject(getUserProject()); + } + + @Test(groups = "live") + public void testInsertFirewall() { + + assertOperationDoneSucessfully(api().create(firewall), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testInsertFirewall") + public void testUpdateFirewall() { + + // replace 22 with 23 + firewall = firewall.toBuilder() + .allowed(ImmutableSet.of( + Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(23) + .build())) + .build(); + + assertOperationDoneSucessfully(api().update(firewall.getName(), firewall), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testUpdateFirewall") + public void testPatchFirewall() { + + // readd 22 with "patch" semantics + firewall = firewall.toBuilder() + .allowed(ImmutableSet.of( + Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(22) + .build(), + Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(23) + .build())) + .build(); + + assertOperationDoneSucessfully(api().update(firewall.getName(), firewall), TIME_WAIT); + + } + + @Test(groups = "live", dependsOnMethods = "testInsertFirewall") + public void testGetFirewall() { + + Firewall firewall = api().get(FIREWALL_NAME); + assertNotNull(firewall); + assertFirewallEquals(firewall, this.firewall); + } + + @Test(groups = "live", dependsOnMethods = "testGetFirewall") + public void testListFirewall() { + + PagedIterable firewalls = api().list(new ListOptions.Builder() + .filter("name eq " + FIREWALL_NAME)); + + List firewallsAsList = Lists.newArrayList(firewalls.concat()); + + assertEquals(firewallsAsList.size(), 1); + + assertFirewallEquals(getOnlyElement(firewallsAsList), + firewall.toBuilder() + .addAllowed(Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPort(23) + .build()) + .build()); + + } + + @Test(groups = "live", dependsOnMethods = "testListFirewall") + public void testDeleteFirewall() { + + assertOperationDoneSucessfully(api().delete(FIREWALL_NAME), TIME_WAIT); + } + + private void assertFirewallEquals(Firewall result, Firewall expected) { + assertEquals(result.getName(), expected.getName()); + assertEquals(getOnlyElement(result.getSourceRanges()), getOnlyElement(expected.getSourceRanges())); + assertEquals(getOnlyElement(result.getSourceTags()), getOnlyElement(expected.getSourceTags())); + assertEquals(getOnlyElement(result.getTargetTags()), getOnlyElement(expected.getTargetTags())); + assertEquals(result.getAllowed(), expected.getAllowed()); + } + +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallListTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallListTest.java new file mode 100644 index 0000000000..4daf4d6736 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallListTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.parse; + +import com.google.common.collect.ImmutableSet; +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.domain.ListPage; +import org.jclouds.googlecompute.domain.Resource; +import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest; +import org.testng.annotations.Test; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; +import java.net.URI; + +/** + * @author David Alves + */ +@Test(groups = "unit") +public class ParseFirewallListTest extends BaseGoogleComputeParseTest> { + + @Override + public String resource() { + return "/firewall_list.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public ListPage expected() { + return ListPage.builder() + .kind(Resource.Kind.FIREWALL_LIST) + .id("projects/google/firewalls") + .selfLink(URI.create("https://www.googleapis.com/compute/v1beta13/projects/google/firewalls")) + .items(ImmutableSet.of( + new ParseFirewallTest().expected() + , Firewall.builder() + .id("12862241067393040785") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-04-13T03:05:04.365")) + .selfLink(URI.create("https://www.googleapis" + + ".com/compute/v1beta13/projects/google/firewalls/default-ssh")) + .name("default-ssh") + .description("SSH allowed from anywhere") + .network(URI.create("https://www.googleapis" + + ".com/compute/v1beta13/projects/google/networks/default")) + .addSourceRange("0.0.0.0/0") + .addAllowed(Firewall.Rule.builder() + .IPProtocol(Firewall.Rule.IPProtocol.TCP) + .addPort(22).build()) + .build() + )) + .build(); + } +} diff --git a/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallTest.java b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallTest.java new file mode 100644 index 0000000000..af5125d103 --- /dev/null +++ b/labs/google-compute/src/test/java/org/jclouds/googlecompute/parse/ParseFirewallTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.googlecompute.parse; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.googlecompute.domain.Firewall; +import org.jclouds.googlecompute.internal.BaseGoogleComputeParseTest; +import org.testng.annotations.Test; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; +import java.net.URI; + +import static org.jclouds.googlecompute.domain.Firewall.Rule.IPProtocol; + +/** + * @author David Alves + */ +@Test(groups = "unit") +public class ParseFirewallTest extends BaseGoogleComputeParseTest { + + @Override + public String resource() { + return "/firewall_get.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public Firewall expected() { + return Firewall.builder() + .id("12862241031274216284") + .creationTimestamp(new SimpleDateFormatDateService().iso8601DateParse("2012-04-13T03:05:02.855")) + .selfLink(URI.create("https://www.googleapis.com/compute/v1beta13/projects/google/firewalls/default" + + "-allow-internal")) + .name("default-allow-internal") + .description("Internal traffic from default allowed") + .network(URI.create("https://www.googleapis.com/compute/v1beta13/projects/google/networks/default")) + .addSourceRange("10.0.0.0/8") + .addAllowed(Firewall.Rule.builder() + .IPProtocol(IPProtocol.TCP) + .addPortRange(1, 65535).build()) + .addAllowed(Firewall.Rule.builder() + .IPProtocol(IPProtocol.UDP) + .addPortRange(1, 65535).build()) + .addAllowed(Firewall.Rule.builder() + .IPProtocol(IPProtocol.ICMP).build()) + .build(); + + } +} diff --git a/labs/google-compute/src/test/resources/firewall_get.json b/labs/google-compute/src/test/resources/firewall_get.json new file mode 100644 index 0000000000..4fa8e2fdd5 --- /dev/null +++ b/labs/google-compute/src/test/resources/firewall_get.json @@ -0,0 +1,30 @@ +{ + + "kind": "compute#firewall", + "id": "12862241031274216284", + "creationTimestamp": "2012-04-13T03:05:02.855", + "selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/firewalls/default-allow-internal", + "name": "default-allow-internal", + "description": "Internal traffic from default allowed", + "network": "https://www.googleapis.com/compute/v1beta13/projects/google/networks/default", + "sourceRanges": [ + "10.0.0.0/8" + ], + "allowed": [ + { + "IPProtocol": "tcp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "udp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "icmp" + } + ] +} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/firewall_insert.json b/labs/google-compute/src/test/resources/firewall_insert.json new file mode 100644 index 0000000000..0410eaa6fc --- /dev/null +++ b/labs/google-compute/src/test/resources/firewall_insert.json @@ -0,0 +1 @@ +{"network":"https://www.googleapis.com/compute/v1beta13/projects/myproject/networks/default","sourceRanges":["10.0.1.0/32"],"sourceTags":["tag1"],"targetTags":["tag2"],"allowed":[{"IPProtocol":"tcp","ports":["22","23-24"]}],"kind":"compute#firewall","name":"myfw"} \ No newline at end of file diff --git a/labs/google-compute/src/test/resources/firewall_list.json b/labs/google-compute/src/test/resources/firewall_list.json new file mode 100644 index 0000000000..a3a8535854 --- /dev/null +++ b/labs/google-compute/src/test/resources/firewall_list.json @@ -0,0 +1,58 @@ +{ + "kind": "compute#firewallList", + "id": "projects/google/firewalls", + "selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/firewalls", + "items": [ + { + + "kind": "compute#firewall", + "id": "12862241031274216284", + "creationTimestamp": "2012-04-13T03:05:02.855", + "selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/firewalls/default-allow-internal", + "name": "default-allow-internal", + "description": "Internal traffic from default allowed", + "network": "https://www.googleapis.com/compute/v1beta13/projects/google/networks/default", + "sourceRanges": [ + "10.0.0.0/8" + ], + "allowed": [ + { + "IPProtocol": "tcp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "udp", + "ports": [ + "1-65535" + ] + }, + { + "IPProtocol": "icmp" + } + ] + }, + { + + "kind": "compute#firewall", + "id": "12862241067393040785", + "creationTimestamp": "2012-04-13T03:05:04.365", + "selfLink": "https://www.googleapis.com/compute/v1beta13/projects/google/firewalls/default-ssh", + "name": "default-ssh", + "description": "SSH allowed from anywhere", + "network": "https://www.googleapis.com/compute/v1beta13/projects/google/networks/default", + "sourceRanges": [ + "0.0.0.0/0" + ], + "allowed": [ + { + "IPProtocol": "tcp", + "ports": [ + "22" + ] + } + ] + } + ] +} \ No newline at end of file