diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackParserModule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackParserModule.java index 0ac02f2c15..065662b09a 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackParserModule.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackParserModule.java @@ -28,6 +28,7 @@ import javax.inject.Singleton; import org.jclouds.cloudstack.domain.Account; import org.jclouds.cloudstack.domain.Account.State; +import org.jclouds.cloudstack.domain.FirewallRule; import org.jclouds.cloudstack.domain.LoadBalancerRule; import org.jclouds.cloudstack.domain.PortForwardingRule; import org.jclouds.cloudstack.domain.User; @@ -46,20 +47,21 @@ import com.google.inject.TypeLiteral; /** * Configures the cloudstack parsers. - * - * @author Adrian Cole + * + * @author Adrian Cole, Andrei Savu */ public class CloudStackParserModule extends AbstractModule { - public static class PortForwardingRuleAdaptor implements JsonSerializer, JsonDeserializer { + @Singleton + public static class PortForwardingRuleAdapter implements JsonSerializer, JsonDeserializer { public JsonElement serialize(PortForwardingRule src, Type typeOfSrc, JsonSerializationContext context) { return context.serialize(src); } public PortForwardingRule deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - return apply(context. deserialize(json, PortForwardingRuleInternal.class)); + throws JsonParseException { + return apply(context.deserialize(json, PortForwardingRuleInternal.class)); } public PortForwardingRule apply(PortForwardingRuleInternal in) { @@ -85,10 +87,10 @@ public class CloudStackParserModule extends AbstractModule { private long IPAddressId; @SerializedName("privateport") private int privatePort; - private String protocol; + private PortForwardingRule.Protocol protocol; @SerializedName("publicport") public int publicPort; - private String state; + private PortForwardingRule.State state; @SerializedName("virtualmachinedisplayname") private String virtualMachineDisplayName; @SerializedName("virtualmachineid") @@ -104,6 +106,52 @@ public class CloudStackParserModule extends AbstractModule { } } + @Singleton + public static class FirewallRuleAdapter implements JsonSerializer, JsonDeserializer { + + public JsonElement serialize(FirewallRule src, Type typeOfSrc, JsonSerializationContext context) { + return context.serialize(src); + } + + public FirewallRule deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return apply(context.deserialize(json, FirewallRuleInternal.class)); + } + + public FirewallRule apply(FirewallRuleInternal in) { + Set cidrSet; + if (in.CIDRs != null) { + String[] elements = in.CIDRs.split(","); + cidrSet = Sets.newTreeSet(Arrays.asList(elements)); + } else { + cidrSet = Collections.emptySet(); + } + return FirewallRule.builder().id(in.id).CIDRs(cidrSet).startPort(in.startPort).endPort(in.endPort) + .icmpCode(in.icmpCode).icmpType(in.icmpType).ipAddress(in.ipAddress).ipAddressId(in.ipAddressId) + .protocol(in.protocol).state(in.state).build(); + } + + static final class FirewallRuleInternal { + private long id; + @SerializedName("cidrlist") + private String CIDRs; + @SerializedName("startport") + private int startPort; + @SerializedName("endport") + private int endPort; + @SerializedName("icmpcode") + private String icmpCode; + @SerializedName("icmptype") + private String icmpType; + @SerializedName("ipaddress") + private String ipAddress; + @SerializedName("ipaddressid") + private long ipAddressId; + private FirewallRule.Protocol protocol; + private FirewallRule.State state; + } + } + @Singleton public static class LoadBalancerRuleAdapter implements JsonSerializer, JsonDeserializer { @@ -112,8 +160,8 @@ public class CloudStackParserModule extends AbstractModule { } public LoadBalancerRule deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - return apply(context. deserialize(json, LoadBalancerRuleInternal.class)); + throws JsonParseException { + return apply(context.deserialize(json, LoadBalancerRuleInternal.class)); } public LoadBalancerRule apply(LoadBalancerRuleInternal in) { @@ -157,22 +205,22 @@ public class CloudStackParserModule extends AbstractModule { } public Account deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - return apply(context. deserialize(json, AccountInternal.class)); + throws JsonParseException { + return apply(context.deserialize(json, AccountInternal.class)); } public Account apply(AccountInternal in) { return Account.builder().id(in.id).type(in.type).domain(in.domain).domainId(in.domainId) - .IPsAvailable(nullIfUnlimited(in.IPsAvailable)).IPLimit(nullIfUnlimited(in.IPLimit)).IPs(in.IPs) - .cleanupRequired(in.cleanupRequired).name(in.name).receivedBytes(in.receivedBytes) - .sentBytes(in.sentBytes).snapshotsAvailable(nullIfUnlimited(in.snapshotsAvailable)) - .snapshotLimit(nullIfUnlimited(in.snapshotLimit)).snapshots(in.snapshots).state(in.state) - .templatesAvailable(nullIfUnlimited(in.templatesAvailable)) - .templateLimit(nullIfUnlimited(in.templateLimit)).templates(in.templates) - .VMsAvailable(nullIfUnlimited(in.VMsAvailable)).VMLimit(nullIfUnlimited(in.VMLimit)) - .VMsRunning(in.VMsRunning).VMsStopped(in.VMsStopped).VMs(in.VMs) - .volumesAvailable(nullIfUnlimited(in.volumesAvailable)).volumeLimit(nullIfUnlimited(in.volumeLimit)) - .volumes(in.volumes).users(in.users).build(); + .IPsAvailable(nullIfUnlimited(in.IPsAvailable)).IPLimit(nullIfUnlimited(in.IPLimit)).IPs(in.IPs) + .cleanupRequired(in.cleanupRequired).name(in.name).receivedBytes(in.receivedBytes) + .sentBytes(in.sentBytes).snapshotsAvailable(nullIfUnlimited(in.snapshotsAvailable)) + .snapshotLimit(nullIfUnlimited(in.snapshotLimit)).snapshots(in.snapshots).state(in.state) + .templatesAvailable(nullIfUnlimited(in.templatesAvailable)) + .templateLimit(nullIfUnlimited(in.templateLimit)).templates(in.templates) + .VMsAvailable(nullIfUnlimited(in.VMsAvailable)).VMLimit(nullIfUnlimited(in.VMLimit)) + .VMsRunning(in.VMsRunning).VMsStopped(in.VMsStopped).VMs(in.VMs) + .volumesAvailable(nullIfUnlimited(in.volumesAvailable)).volumeLimit(nullIfUnlimited(in.volumeLimit)) + .volumes(in.volumes).users(in.users).build(); } static final class AccountInternal { @@ -237,10 +285,11 @@ public class CloudStackParserModule extends AbstractModule { @Override protected void configure() { bind(new TypeLiteral>() { - }).toInstance(ImmutableMap. of( + }).toInstance(ImmutableMap.of( Account.class, new BreakGenericSetAdapter(), LoadBalancerRule.class, new LoadBalancerRuleAdapter(), - PortForwardingRule.class, new PortForwardingRuleAdaptor() + PortForwardingRule.class, new PortForwardingRuleAdapter(), + FirewallRule.class, new FirewallRuleAdapter() )); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java new file mode 100644 index 0000000000..baf5fe6f3c --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/FirewallRule.java @@ -0,0 +1,288 @@ +/** + * 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.cloudstack.domain; + +import com.google.common.base.CaseFormat; +import com.google.common.collect.ImmutableSet; +import com.google.gson.annotations.SerializedName; +import org.omg.PortableInterceptor.ACTIVE; + +import java.util.Set; + +/** + * @author Andrei Savu + */ +public class FirewallRule implements Comparable { + + public static enum Protocol { + TCP, + UDP, + ICMP, + UNKNOWN; + + public static Protocol fromValue(String value) { + try { + return valueOf(value.toUpperCase()); + } catch(IllegalArgumentException e) { + return UNKNOWN; + } + } + + @Override + public String toString() { + return name().toUpperCase(); + } + } + + public static enum State { + STAGED, // Rule been created but has never got through network rule conflict detection. + // Rules in this state can not be sent to network elements. + ADD, // Add means the rule has been created and has gone through network rule conflict detection. + ACTIVE, // Rule has been sent to the network elements and reported to be active. + DELETEING, // Revoke means this rule has been revoked. If this rule has been sent to the + // network elements, the rule will be deleted from database. + UNKNOWN; + + public static State fromValue(String value) { + try { + return valueOf(value.toUpperCase()); + } catch(IllegalArgumentException e) { + return UNKNOWN; + } + } + + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private long id; + private Set CIDRs; + + private int startPort; + private int endPort; + + private String icmpCode; + private String icmpType; + + private String ipAddress; + private long ipAddressId; + + private Protocol protocol; + private State state; + + public Builder id(long id) { + this.id = id; + return this; + } + + public Builder CIDRs(Set CIDRs) { + this.CIDRs = ImmutableSet.copyOf(CIDRs); + return this; + } + + public Builder startPort(int startPort) { + this.startPort = startPort; + return this; + } + + public Builder endPort(int endPort) { + this.endPort = endPort; + return this; + } + + public Builder icmpCode(String icmpCode) { + this.icmpCode = icmpCode; + return this; + } + + public Builder icmpType(String icmpType) { + this.icmpType = icmpType; + return this; + } + + public Builder ipAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + public Builder ipAddressId(long ipAddressId) { + this.ipAddressId = ipAddressId; + return this; + } + + public Builder protocol(Protocol protocol) { + this.protocol = protocol; + return this; + } + + public Builder state(State state) { + this.state = state; + return this; + } + + public FirewallRule build() { + return new FirewallRule(id, CIDRs, startPort, endPort, icmpCode, + icmpType, ipAddress, ipAddressId, protocol, state); + } + } + + private long id; + @SerializedName("cidrlist") + private Set CIDRs; + @SerializedName("startport") + private int startPort; + @SerializedName("endport") + private int endPort; + @SerializedName("icmpcode") + private String icmpCode; + @SerializedName("icmptype") + private String icmpType; + @SerializedName("ipaddress") + private String ipAddress; + @SerializedName("ipaddressid") + private long ipAddressId; + private Protocol protocol; + private State state; + + public FirewallRule(long id, Set CIDRs, int startPort, int endPort, + String icmpCode, String icmpType, String ipAddress, long ipAddressId, + Protocol protocol, State state) { + this.id = id; + this.CIDRs = ImmutableSet.copyOf(CIDRs); + this.startPort = startPort; + this.endPort = endPort; + this.icmpCode = icmpCode; + this.icmpType = icmpType; + this.ipAddress = ipAddress; + this.ipAddressId = ipAddressId; + this.protocol = protocol; + this.state = state; + } + + @Override + public int compareTo(FirewallRule arg0) { + return new Long(id).compareTo(arg0.getId()); + } + + public long getId() { + return id; + } + + public Set getCIDRs() { + return CIDRs; + } + + public int getStartPort() { + return startPort; + } + + public int getEndPort() { + return endPort; + } + + public String getIcmpCode() { + return icmpCode; + } + + public String getIcmpType() { + return icmpType; + } + + public String getIpAddress() { + return ipAddress; + } + + public long getIpAddressId() { + return ipAddressId; + } + + public Protocol getProtocol() { + return protocol; + } + + public State getState() { + return state; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + FirewallRule that = (FirewallRule) o; + + if (endPort != that.endPort) return false; + if (id != that.id) return false; + if (startPort != that.startPort) return false; + if (CIDRs != null ? !CIDRs.equals(that.CIDRs) : that.CIDRs != null) + return false; + if (icmpCode != null ? !icmpCode.equals(that.icmpCode) : that.icmpCode != null) + return false; + if (icmpType != null ? !icmpType.equals(that.icmpType) : that.icmpType != null) + return false; + if (ipAddress != null ? !ipAddress.equals(that.ipAddress) : that.ipAddress != null) + return false; + if (ipAddressId != that.ipAddressId) + return false; + if (protocol != null ? !protocol.equals(that.protocol) : that.protocol != null) + return false; + if (state != null ? !state.equals(that.state) : that.state != null) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + (CIDRs != null ? CIDRs.hashCode() : 0); + result = 31 * result + startPort; + result = 31 * result + endPort; + result = 31 * result + (icmpCode != null ? icmpCode.hashCode() : 0); + result = 31 * result + (icmpType != null ? icmpType.hashCode() : 0); + result = 31 * result + (ipAddress != null ? ipAddress.hashCode() : 0); + result = 31 * result + (int) (ipAddressId ^ (ipAddressId >>> 32)); + result = 31 * result + (protocol != null ? protocol.hashCode() : 0); + result = 31 * result + (state != null ? state.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "FirewallRule{" + + "id=" + id + + ", CIDRs='" + CIDRs + '\'' + + ", startPort=" + startPort + + ", endPort=" + endPort + + ", icmpCode='" + icmpCode + '\'' + + ", icmpType='" + icmpType + '\'' + + ", ipAddress='" + ipAddress + '\'' + + ", ipAddressId='" + ipAddressId + '\'' + + ", protocol='" + protocol + '\'' + + ", state='" + state + '\'' + + '}'; + } +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java index e0dada1791..67c8ddb8ce 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/PortForwardingRule.java @@ -20,15 +20,58 @@ package org.jclouds.cloudstack.domain; import java.util.Set; -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; +import com.google.common.base.CaseFormat; import com.google.common.collect.ImmutableSet; import com.google.gson.annotations.SerializedName; /** - * @author Adrian Cole + * @author Adrian Cole, Andrei Savu */ public class PortForwardingRule implements Comparable { + + public static enum Protocol { + TCP, + UDP, + ICMP, + UNKNOWN; + + public static Protocol fromValue(String value) { + try { + return valueOf(value.toUpperCase()); + } catch (IllegalArgumentException e) { + return UNKNOWN; + } + } + + @Override + public String toString() { + return name().toLowerCase(); + } + } + + public static enum State { + STAGED, // Rule been created but has never got through network rule conflict detection. + // Rules in this state can not be sent to network elements. + ADD, // Add means the rule has been created and has gone through network rule conflict detection. + ACTIVE, // Rule has been sent to the network elements and reported to be active. + DELETEING, // Revoke means this rule has been revoked. If this rule has been sent to the + // network elements, the rule will be deleted from database. + UNKNOWN; + + public static State fromValue(String value) { + try { + return valueOf(value.toUpperCase()); + } catch (IllegalArgumentException e) { + return UNKNOWN; + } + } + + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()); + } + } + public static Builder builder() { return new Builder(); } @@ -38,9 +81,9 @@ public class PortForwardingRule implements Comparable { private String IPAddress; private long IPAddressId; private int privatePort; - private String protocol; + private Protocol protocol; public int publicPort; - private String state; + private State state; private String virtualMachineDisplayName; public long virtualMachineId; private String virtualMachineName; @@ -68,7 +111,7 @@ public class PortForwardingRule implements Comparable { return this; } - public Builder protocol(String protocol) { + public Builder protocol(Protocol protocol) { this.protocol = protocol; return this; } @@ -78,7 +121,7 @@ public class PortForwardingRule implements Comparable { return this; } - public Builder state(String state) { + public Builder state(State state) { this.state = state; return this; } @@ -115,7 +158,7 @@ public class PortForwardingRule implements Comparable { public PortForwardingRule build() { return new PortForwardingRule(id, IPAddress, IPAddressId, privatePort, protocol, publicPort, state, - virtualMachineDisplayName, virtualMachineId, virtualMachineName, CIDRs, privateEndPort, publicEndPort); + virtualMachineDisplayName, virtualMachineId, virtualMachineName, CIDRs, privateEndPort, publicEndPort); } } @@ -126,10 +169,10 @@ public class PortForwardingRule implements Comparable { private long IPAddressId; @SerializedName("privateport") private int privatePort; - private String protocol; + private Protocol protocol; @SerializedName("publicport") public int publicPort; - private String state; + private State state; @SerializedName("virtualmachinedisplayname") private String virtualMachineDisplayName; @SerializedName("virtualmachineid") @@ -143,8 +186,8 @@ public class PortForwardingRule implements Comparable { @SerializedName("publicendport") private int publicEndPort; - public PortForwardingRule(long id, String iPAddress, long iPAddressId, int privatePort, String protocol, - int publicPort, String state, String virtualMachineDisplayName, long virtualMachineId, + public PortForwardingRule(long id, String iPAddress, long iPAddressId, int privatePort, Protocol protocol, + int publicPort, State state, String virtualMachineDisplayName, long virtualMachineId, String virtualMachineName, Set CIDRs, int privateEndPort, int publicEndPort) { this.id = id; this.IPAddress = iPAddress; @@ -197,7 +240,7 @@ public class PortForwardingRule implements Comparable { /** * @return the protocol of the port forwarding rule */ - public String getProtocol() { + public Protocol getProtocol() { return protocol; } @@ -211,7 +254,7 @@ public class PortForwardingRule implements Comparable { /** * @return the state of the rule */ - public String getState() { + public State getState() { return state; } @@ -324,20 +367,20 @@ public class PortForwardingRule implements Comparable { @Override public String toString() { return "PortForwardingRule{" + - "id=" + id + - ", IPAddress='" + IPAddress + '\'' + - ", IPAddressId=" + IPAddressId + - ", privatePort=" + privatePort + - ", protocol='" + protocol + '\'' + - ", publicPort=" + publicPort + - ", state='" + state + '\'' + - ", virtualMachineDisplayName='" + virtualMachineDisplayName + '\'' + - ", virtualMachineId=" + virtualMachineId + - ", virtualMachineName='" + virtualMachineName + '\'' + - ", CIDRs=" + getCIDRs() + - ", privateEndPort=" + privateEndPort + - ", publicEndPort=" + publicEndPort + - '}'; + "id=" + id + + ", IPAddress='" + IPAddress + '\'' + + ", IPAddressId=" + IPAddressId + + ", privatePort=" + privatePort + + ", protocol='" + protocol + '\'' + + ", publicPort=" + publicPort + + ", state='" + state + '\'' + + ", virtualMachineDisplayName='" + virtualMachineDisplayName + '\'' + + ", virtualMachineId=" + virtualMachineId + + ", virtualMachineName='" + virtualMachineName + '\'' + + ", CIDRs=" + getCIDRs() + + ", privateEndPort=" + privateEndPort + + ", publicEndPort=" + publicEndPort + + '}'; } } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallAsyncClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallAsyncClient.java index 85b63b04eb..5c9ef48e80 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallAsyncClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallAsyncClient.java @@ -26,15 +26,20 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.FirewallRule; import org.jclouds.cloudstack.domain.PortForwardingRule; import org.jclouds.cloudstack.filters.QuerySigner; +import org.jclouds.cloudstack.options.CreateFirewallRuleOptions; +import org.jclouds.cloudstack.options.ListFirewallRulesOptions; import org.jclouds.cloudstack.options.ListPortForwardingRulesOptions; import org.jclouds.rest.annotations.ExceptionParser; +import org.jclouds.rest.annotations.OnlyElement; import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.Unwrap; import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import com.google.common.util.concurrent.ListenableFuture; @@ -42,15 +47,54 @@ import com.google.common.util.concurrent.ListenableFuture; /** * Provides asynchronous access to cloudstack via their REST API. *

- * + * + * @author Adrian Cole * @see FirewallClient * @see - * @author Adrian Cole */ @RequestFilters(QuerySigner.class) @QueryParams(keys = "response", values = "json") public interface FirewallAsyncClient { + /** + * @see FirewallClient#listFirewallRules + */ + @GET + @QueryParams(keys = "command", values = "listFirewallRules") + @SelectJson("firewallrule") + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) + ListenableFuture> listFirewallRules(ListFirewallRulesOptions... options); + + /** + * @see FirewallClient#getFirewallRule + */ + @GET + @QueryParams(keys = "command", values = "listFirewallRules") + @SelectJson("firewallrule") + @OnlyElement + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getFirewallRule(@QueryParam("id") long id); + + /** + * @see FirewallClient#createFirewallRuleForIpAndProtocol + */ + @GET + @QueryParams(keys = "command", values = "createFirewallRule") + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + ListenableFuture createFirewallRuleForIpAndProtocol(@QueryParam("ipaddressid") long ipAddressId, + @QueryParam("protocol") FirewallRule.Protocol protocol, CreateFirewallRuleOptions... options); + + /** + * @see FirewallClient#deleteFirewallRule + */ + @GET + @QueryParams(keys = "command", values = "deleteFirewallRule") + @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + ListenableFuture deleteFirewallRule(@QueryParam("id") long id); + /** * @see FirewallClient#listPortForwardingRules */ @@ -61,6 +105,17 @@ public interface FirewallAsyncClient { @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class) ListenableFuture> listPortForwardingRules(ListPortForwardingRulesOptions... options); + /** + * @see FirewallClient#getPortForwardingRule + */ + @GET + @QueryParams(keys = "command", values = "listPortForwardingRules") + @SelectJson("portforwardingrule") + @OnlyElement + @Consumes(MediaType.APPLICATION_JSON) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getPortForwardingRule(@QueryParam("id") long id); + /** * @see FirewallClient#createPortForwardingRuleForVirtualMachine */ @@ -69,9 +124,9 @@ public interface FirewallAsyncClient { @Unwrap @Consumes(MediaType.APPLICATION_JSON) ListenableFuture createPortForwardingRuleForVirtualMachine( - @QueryParam("virtualmachineid") long virtualMachineId, @QueryParam("ipaddressid") long IPAddressId, - @QueryParam("protocol") String protocol, @QueryParam("privateport") int privatePort, - @QueryParam("publicport") int publicPort); + @QueryParam("ipaddressid") long ipAddressId, @QueryParam("protocol") PortForwardingRule.Protocol protocol, + @QueryParam("publicport") int publicPort, @QueryParam("virtualmachineid") long virtualMachineId, + @QueryParam("privateport") int privatePort); /** * @see FirewallClient#deletePortForwardingRule diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallClient.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallClient.java index 34800160f1..ae02685702 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallClient.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/features/FirewallClient.java @@ -22,7 +22,10 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.FirewallRule; import org.jclouds.cloudstack.domain.PortForwardingRule; +import org.jclouds.cloudstack.options.CreateFirewallRuleOptions; +import org.jclouds.cloudstack.options.ListFirewallRulesOptions; import org.jclouds.cloudstack.options.ListPortForwardingRulesOptions; import org.jclouds.concurrent.Timeout; @@ -36,6 +39,49 @@ import org.jclouds.concurrent.Timeout; */ @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS) public interface FirewallClient { + + /** + * List the firewall rules + * + * @param options + * if present, how to constrain the list. + * @return + * set of firewall rules or empty set if no rules are found + */ + Set listFirewallRules(ListFirewallRulesOptions... options); + + /** + * Get a firewall rule by ID + * + * @param id + * the ID of the firewall rule + * @return + * firewall rule instance or null + */ + FirewallRule getFirewallRule(long id); + + /** + * Create new firewall rule for a specific IP address + * + * @param ipAddressId + * the IP address id of the port forwarding rule + * @param protocol + * the protocol for the firewall rule. Valid values are TCP/UDP/ICMP + * @param options + * optional arguments for firewall rule creation + * @return + */ + AsyncCreateResponse createFirewallRuleForIpAndProtocol(long ipAddressId, + FirewallRule.Protocol protocol, CreateFirewallRuleOptions... options); + + /** + * Deletes a firewall rule + * + * @param id + * the ID of the firewall rule + */ + Void deleteFirewallRule(long id); + /** * List the port forwarding rules * @@ -46,24 +92,33 @@ public interface FirewallClient { */ Set listPortForwardingRules(ListPortForwardingRulesOptions... options); + /** + * Get a port forwarding rule by ID + * + * @param id + * port forwarding rule ID + * @return + * rule instance or null + */ + PortForwardingRule getPortForwardingRule(long id); + /** * Creates an port forwarding rule * - * @param virtualMachineId - * the ID of the virtual machine for the port forwarding rule - * @param IPAddressId - * the public IP address id of the forwarding rule, already - * associated via associatePort + * + * @param ipAddressId * @param protocol * the protocol for the rule. Valid values are TCP or UDP. - * @param privatePort - * the private port of the port forwarding rule * @param publicPort * the public port of the port forwarding rule + * @param virtualMachineId + * the ID of the virtual machine for the port forwarding rule + * @param privatePort + * the private port of the port forwarding rule * @return response used to track creation */ - AsyncCreateResponse createPortForwardingRuleForVirtualMachine(long virtualMachineId, long IPAddressId, - String protocol, int privatePort, int publicPort); + AsyncCreateResponse createPortForwardingRuleForVirtualMachine(long ipAddressId, + PortForwardingRule.Protocol protocol, int publicPort, long virtualMachineId, int privatePort); /** * Deletes an port forwarding rule @@ -71,5 +126,5 @@ public interface FirewallClient { * @param id * the id of the forwarding rule */ - void deletePortForwardingRule(long id); + Void deletePortForwardingRule(long id); } diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateFirewallRuleOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateFirewallRuleOptions.java new file mode 100644 index 0000000000..00b37bd525 --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/CreateFirewallRuleOptions.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.cloudstack.options; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; +import org.jclouds.http.options.BaseHttpRequestOptions; + +import java.util.Set; + +/** + * Options used to control how a firewall rule is created + * + * @see + * @author Andrei Savu + */ +public class CreateFirewallRuleOptions extends BaseHttpRequestOptions { + + public static final CreateFirewallRuleOptions NONE = new CreateFirewallRuleOptions(); + + /** + * @param CIDRs + * the list of CIDRs to forward traffic from + */ + public CreateFirewallRuleOptions CIDRs(Set CIDRs) { + this.queryParameters.replaceValues("cidrlist", ImmutableSet.of(Joiner.on(",").join(CIDRs))); + return this; + } + + /** + * @param startPort + * the starting port of firewall rule + */ + public CreateFirewallRuleOptions startPort(int startPort) { + this.queryParameters.replaceValues("startport", ImmutableSet.of(startPort + "")); + return this; + } + + /** + * @param endPort + * the ending port of firewall rule + */ + public CreateFirewallRuleOptions endPort(int endPort) { + this.queryParameters.replaceValues("endport", ImmutableSet.of(endPort + "")); + return this; + } + + /** + * @param icmpCode + * error code for this icmp message + */ + public CreateFirewallRuleOptions icmpCode(String icmpCode) { + this.queryParameters.replaceValues("icmpcode", ImmutableSet.of(icmpCode)); + return this; + } + + /** + * @param icmpType + * type of the icmp message being sent + */ + public CreateFirewallRuleOptions icmpType(String icmpType) { + this.queryParameters.replaceValues("icmptype", ImmutableSet.of(icmpType)); + return this; + } + + public static class Builder { + + /** + * @see CreateFirewallRuleOptions#CIDRs + */ + public static CreateFirewallRuleOptions CIDRs(Set CIDRs) { + CreateFirewallRuleOptions options = new CreateFirewallRuleOptions(); + return options.CIDRs(CIDRs); + } + + /** + * @see CreateFirewallRuleOptions#startPort + */ + public static CreateFirewallRuleOptions startPort(int startPort) { + CreateFirewallRuleOptions options = new CreateFirewallRuleOptions(); + return options.startPort(startPort); + } + + /** + * @see CreateFirewallRuleOptions#endPort + */ + public static CreateFirewallRuleOptions endPort(int endPort) { + CreateFirewallRuleOptions options = new CreateFirewallRuleOptions(); + return options.endPort(endPort); + } + + /** + * @see CreateFirewallRuleOptions#icmpCode + */ + public static CreateFirewallRuleOptions icmpCode(String icmpCode) { + CreateFirewallRuleOptions options = new CreateFirewallRuleOptions(); + return options.icmpCode(icmpCode); + } + + /** + * @see CreateFirewallRuleOptions#icmpType + */ + public static CreateFirewallRuleOptions icmpType(String icmpType) { + CreateFirewallRuleOptions options = new CreateFirewallRuleOptions(); + return options.icmpType(icmpType); + } + } +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java new file mode 100644 index 0000000000..4b683e978a --- /dev/null +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListFirewallRulesOptions.java @@ -0,0 +1,147 @@ +/** + * 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.cloudstack.options; + +import com.google.common.collect.ImmutableSet; + +/** + * Options used to control what firewall rules are returned + * + * @see + * @author Andrei Savu + */ +public class ListFirewallRulesOptions extends AccountInDomainOptions { + + public static final ListFirewallRulesOptions NONE = new ListFirewallRulesOptions(); + + /** + * @param id + * firewall rule ID + */ + public ListFirewallRulesOptions id(long id) { + this.queryParameters.replaceValues("id", ImmutableSet.of(id + "")); + return this; + } + + /** + * @param ipAddressId + * the id of IP address of the firwall services + */ + public ListFirewallRulesOptions ipAddressId(long ipAddressId) { + this.queryParameters.replaceValues("ipaddressid", ImmutableSet.of(ipAddressId + "")); + return this; + } + + /** + * @param keyword + * list by keyword + */ + public ListFirewallRulesOptions keyword(String keyword) { + this.queryParameters.replaceValues("keyword", ImmutableSet.of(keyword)); + return this; + } + + public ListFirewallRulesOptions page(long page) { + this.queryParameters.replaceValues("page", ImmutableSet.of(page + "")); + return this; + } + + public ListFirewallRulesOptions pageSize(long pageSize) { + this.queryParameters.replaceValues("pagesize", ImmutableSet.of(pageSize + "")); + return this; + } + + public static class Builder { + + /** + * @see ListFirewallRulesOptions#id + */ + public static ListFirewallRulesOptions id(long id) { + ListFirewallRulesOptions options = new ListFirewallRulesOptions(); + return options.id(id); + } + + /** + * @see ListFirewallRulesOptions#ipAddressId + */ + public static ListFirewallRulesOptions ipAddressId(long ipAddressId) { + ListFirewallRulesOptions options = new ListFirewallRulesOptions(); + return options.ipAddressId(ipAddressId); + } + + /** + * @see ListFirewallRulesOptions#keyword + */ + public static ListFirewallRulesOptions keyword(String keyword) { + ListFirewallRulesOptions options = new ListFirewallRulesOptions(); + return options.keyword(keyword); + } + + /** + * @see ListFirewallRulesOptions#page + */ + public static ListFirewallRulesOptions page(long page) { + ListFirewallRulesOptions options = new ListFirewallRulesOptions(); + return options.page(page); + } + + /** + * @see ListFirewallRulesOptions#pageSize + */ + public static ListFirewallRulesOptions pageSize(long pageSize) { + ListFirewallRulesOptions options = new ListFirewallRulesOptions(); + return options.pageSize(pageSize); + } + + /** + * @see ListFirewallRulesOptions#accountInDomain + */ + public static ListFirewallRulesOptions accountInDomain(String account, long domain) { + ListFirewallRulesOptions options = new ListFirewallRulesOptions(); + return options.accountInDomain(account, domain); + } + + /** + * @see ListFirewallRulesOptions#domainId + */ + public static ListFirewallRulesOptions domainId(long id) { + ListFirewallRulesOptions options = new ListFirewallRulesOptions(); + return options.domainId(id); + } + + } + + /** + * {@inheritDoc} + */ + @Override + public ListFirewallRulesOptions accountInDomain(String account, long domain) { + return ListFirewallRulesOptions.class.cast(super.accountInDomain(account, domain)); + } + + /** + * {@inheritDoc} + */ + @Override + public ListFirewallRulesOptions domainId(long domainId) { + return ListFirewallRulesOptions.class.cast(super.domainId(domainId)); + } +} diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java index c9b31f0d85..5cf580bed7 100644 --- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java +++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptions.java @@ -22,27 +22,53 @@ import com.google.common.collect.ImmutableSet; /** * Options used to control what port forwarding rules are returned - * - * @see + * * @author Adrian Cole + * @see */ public class ListPortForwardingRulesOptions extends AccountInDomainOptions { public static final ListPortForwardingRulesOptions NONE = new ListPortForwardingRulesOptions(); /** - * @param IPAddressId - * list the rule belonging to this public ip address + * @param id + * lists rule with the specified ID */ - public ListPortForwardingRulesOptions IPAddressId(long IPAddressId) { + public ListPortForwardingRulesOptions id(long id) { + this.queryParameters.replaceValues("id", ImmutableSet.of(id + "")); + return this; + } + + /** + * @param IPAddressId + * list the rule belonging to this public ip address + */ + public ListPortForwardingRulesOptions ipAddressId(long IPAddressId) { this.queryParameters.replaceValues("ipaddressid", ImmutableSet.of(IPAddressId + "")); return this; } public static class Builder { + + /** + * @see ListPortForwardingRulesOptions#id + */ + public static ListPortForwardingRulesOptions id(long id) { + ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions(); + return options.id(id); + } + + /** + * @see ListPortForwardingRulesOptions#ipAddressId + */ + public static ListPortForwardingRulesOptions ipAddressId(long ipAddressId) { + ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions(); + return options.ipAddressId(ipAddressId); + } + /** * @see ListPortForwardingRulesOptions#accountInDomain */ @@ -51,14 +77,6 @@ public class ListPortForwardingRulesOptions extends AccountInDomainOptions { return options.accountInDomain(account, domain); } - /** - * @see ListPortForwardingRulesOptions#IPAddressId - */ - public static ListPortForwardingRulesOptions IPAddressId(long IPAddressId) { - ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions(); - return options.IPAddressId(IPAddressId); - } - /** * @see ListPortForwardingRulesOptions#domainId */ @@ -66,7 +84,6 @@ public class ListPortForwardingRulesOptions extends AccountInDomainOptions { ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions(); return options.domainId(id); } - } /** diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallAsyncClientTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallAsyncClientTest.java index a40ff9376d..1bc2025431 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallAsyncClientTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallAsyncClientTest.java @@ -21,6 +21,7 @@ package org.jclouds.cloudstack.features; import java.io.IOException; import java.lang.reflect.Method; +import org.jclouds.cloudstack.domain.PortForwardingRule; import org.jclouds.cloudstack.options.ListPortForwardingRulesOptions; import org.jclouds.http.HttpRequest; import org.jclouds.http.functions.ParseFirstJsonValueNamed; @@ -64,7 +65,7 @@ public class FirewallAsyncClientTest extends BaseCloudStackAsyncClientTestbuilder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/listfirewallrulesresponse.json")) + .build()) + .getFirewallClient(); + + Set CIDRs = ImmutableSet.of("0.0.0.0/0"); + assertEquals(client.listFirewallRules(), + ImmutableSet.of( + FirewallRule.builder().id(2017).protocol(FirewallRule.Protocol.TCP).startPort(30) + .endPort(35).ipAddressId(2).ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE) + .CIDRs(CIDRs).build(), + FirewallRule.builder().id(2016).protocol(FirewallRule.Protocol.TCP).startPort(22) + .endPort(22).ipAddressId(2).ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE) + .CIDRs(CIDRs).build(), + FirewallRule.builder().id(10).protocol(FirewallRule.Protocol.TCP).startPort(22) + .endPort(22).ipAddressId(8).ipAddress("10.27.27.57").state(FirewallRule.State.ACTIVE) + .CIDRs(CIDRs).build() + )); + } + + public void testListFirewallRulesWhenReponseIs404() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=listFirewallRules&" + + "apiKey=identity&signature=MktZKKH3USVKiC9SlYTSHMCaCcg%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()) + .getFirewallClient(); + + assertEquals(client.listFirewallRules(), ImmutableSet.of()); + } + + public void testGetFirewallRuleWhenResponseIs2xx() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=listFirewallRules&" + + "id=2017&apiKey=identity&signature=0r5iL%2Bzix9rmD07lJIOhY68mYY0%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/getfirewallrulesresponse.json")) + .build()) + .getFirewallClient(); + + assertEquals(client.getFirewallRule(2017), + FirewallRule.builder().id(2017).protocol(FirewallRule.Protocol.TCP).startPort(30) + .endPort(35).ipAddressId(2).ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE) + .CIDRs(ImmutableSet.of("0.0.0.0/0")).build() + ); + } + + public void testGetFirewallRuleWhenResponseIs404() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=listFirewallRules&" + + "id=4&apiKey=identity&signature=PPX5U9kmaS116SgG4Ihf8xK%2BcSE%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()) + .getFirewallClient(); + + assertNull(client.getFirewallRule(4)); + } + + public void testCreateFirewallRuleForIpAndProtocol() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=createFirewallRule&" + + "ipaddressid=2&protocol=TCP&apiKey=identity&signature=d0MZ%2FyhQPAaV%2BYQmfZsQtQL2C28%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/createfirewallrulesresponse.json")) + .build()) + .getFirewallClient(); + + AsyncCreateResponse response = client.createFirewallRuleForIpAndProtocol(2, FirewallRule.Protocol.TCP); + assertEquals(response.getJobId(), 2036); + assertEquals(response.getId(), 2017); + } + + public void testDeleteFirewallRule() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=deleteFirewallRule&id=2015&apiKey=identity&signature=%2FT5FAO2yGPctaPmg7TEtIEFW3EU%3D")) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/deletefirewallrulesresponse.json")) + .build()) + .getFirewallClient(); + + client.deleteFirewallRule(2015); + } + + public void testListPortForwardingRulesWhenResponseIs2xx() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listPortForwardingRules&apiKey=identity&signature=YFBu1VOSkiDKxm0K42sIXJWy%2BBo%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/listportforwardingrulesresponse.json")) + .build()) + .getFirewallClient(); + + Set cidrs = ImmutableSet.of("0.0.0.0/1", "128.0.0.0/1"); + + assertEquals(client.listPortForwardingRules(), + ImmutableSet.of( + PortForwardingRule.builder().id(15).privatePort(22).protocol(PortForwardingRule.Protocol.TCP) + .publicPort(2022).virtualMachineId(3).virtualMachineName("i-3-3-VM").IPAddressId(3) + .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE).CIDRs(cidrs).build(), + PortForwardingRule.builder().id(18).privatePort(22).protocol(PortForwardingRule.Protocol.TCP) + .publicPort(22).virtualMachineId(89).virtualMachineName("i-3-89-VM").IPAddressId(34) + .IPAddress("72.52.126.63").state(PortForwardingRule.State.ACTIVE).build()) + ); + } + + public void testListPortForwardingRulesWhenReponseIs404() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listPortForwardingRules&apiKey=identity&signature=YFBu1VOSkiDKxm0K42sIXJWy%2BBo%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()) + .getFirewallClient(); + + assertEquals(client.listPortForwardingRules(), ImmutableSet.of()); + } + + public void testGetPortForwardingRuleWhenResponseIs2xx() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listPortForwardingRules&id=15&apiKey=identity&signature=ABJsciF4n2tXaiyUmEvc3oYh9MA%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/getportforwardingrulesresponse.json")) + .build()) + .getFirewallClient(); + + Set cidrs = ImmutableSet.of("0.0.0.0/1", "128.0.0.0/1"); + + assertEquals(client.getPortForwardingRule(15), + PortForwardingRule.builder().id(15).privatePort(22).protocol(PortForwardingRule.Protocol.TCP) + .publicPort(2022).virtualMachineId(3).virtualMachineName("i-3-3-VM").IPAddressId(3) + .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE).CIDRs(cidrs).build()); + } + + public void testGetPortForwardingRuleWhenResponseIs404() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=listPortForwardingRules&id=4&apiKey=identity&signature=CTOmmIOGIiZx0YATqh%2FFk0zIplw%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(404) + .build()) + .getFirewallClient(); + + assertNull(client.getPortForwardingRule(4)); + } + + public void testCreatePortForwardingRuleForVirtualMachine() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&command=createPortForwardingRule&" + + "ipaddressid=2&publicport=22&protocol=tcp&virtualmachineid=1234&privateport=22&" + + "apiKey=identity&signature=84dtGzQp0G6k3z3Gkc3F%2FHBNS2Y%3D")) + .headers( + ImmutableMultimap.builder() + .put("Accept", "application/json") + .build()) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/createportforwardingrulesresponse.json")) + .build()) + .getFirewallClient(); + + AsyncCreateResponse response = client.createPortForwardingRuleForVirtualMachine( + 2, PortForwardingRule.Protocol.TCP, 22, 1234, 22); + assertEquals(response.getJobId(), 2035); + assertEquals(response.getId(), 2015); + } + + public void testDeletePortForwardingRule() { + FirewallClient client = requestSendsResponse( + HttpRequest.builder() + .method("GET") + .endpoint( + URI.create("http://localhost:8080/client/api?response=json&" + + "command=deletePortForwardingRule&id=2015&apiKey=identity&signature=2UE7KB3wm5ocmR%2BGMNFKPKfiDo8%3D")) + .build(), + HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResource("/deleteportforwardingrulesresponse.json")) + .build()) + .getFirewallClient(); + + client.deletePortForwardingRule(2015); + } +} \ No newline at end of file diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java index 4ea03459df..836e41405f 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/FirewallClientLiveTest.java @@ -19,18 +19,22 @@ package org.jclouds.cloudstack.features; import static com.google.common.collect.Iterables.find; +import static org.jclouds.cloudstack.predicates.NetworkPredicates.supportsPortForwarding; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.util.NoSuchElementException; import java.util.Set; +import com.google.common.base.Predicates; import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.FirewallRule; import org.jclouds.cloudstack.domain.Network; import org.jclouds.cloudstack.domain.PortForwardingRule; import org.jclouds.cloudstack.domain.PublicIPAddress; import org.jclouds.cloudstack.domain.VirtualMachine; -import org.jclouds.cloudstack.predicates.NetworkPredicates; +import org.jclouds.cloudstack.options.CreateFirewallRuleOptions; +import org.jclouds.logging.Logger; import org.jclouds.net.IPSocket; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; @@ -38,16 +42,21 @@ import org.testng.annotations.Test; import com.google.common.base.Predicate; +import javax.annotation.Nullable; + /** * Tests behavior of {@code FirewallClientLiveTest} - * + * * @author Adrian Cole */ @Test(groups = "live", singleThreaded = true, testName = "FirewallClientLiveTest") public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest { private PublicIPAddress ip = null; private VirtualMachine vm; - private PortForwardingRule rule; + + private FirewallRule firewallRule; + private PortForwardingRule portForwardingRule; + private Network network; private boolean networksDisabled; @@ -56,13 +65,25 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest { super.setupClient(); prefix += "rule"; try { - network = find(client.getNetworkClient().listNetworks(), NetworkPredicates.supportsPortForwarding()); + network = find(client.getNetworkClient().listNetworks(), Predicates.and(supportsPortForwarding(), + new Predicate() { + @Override + public boolean apply(@Nullable Network network) { + return network.isDefault() + && !network.isSecurityGroupEnabled() + && network.getAccount().equals(user.getAccount()); + } + })); + Long defaultTemplate = (imageId != null && !"".equals(imageId)) ? new Long(imageId) : null; + vm = VirtualMachineClientLiveTest.createVirtualMachineInNetwork(network, - defaultTemplateOrPreferredInZone(defaultTemplate, client, network.getZoneId()), client, jobComplete, - virtualMachineRunning); + defaultTemplateOrPreferredInZone(defaultTemplate, client, network.getZoneId()), + client, jobComplete, virtualMachineRunning); + if (vm.getPassword() != null && !loginCredentials.hasPasswordOption()) loginCredentials = loginCredentials.toBuilder().password(vm.getPassword()).build(); + } catch (NoSuchElementException e) { networksDisabled = true; } @@ -71,30 +92,75 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest { public void testCreatePortForwardingRule() throws Exception { if (networksDisabled) return; - while (rule == null) { + while (portForwardingRule == null) { ip = reuseOrAssociate.apply(network); try { - AsyncCreateResponse job = client.getFirewallClient().createPortForwardingRuleForVirtualMachine(vm.getId(), - ip.getId(), "tcp", 22, 22); + AsyncCreateResponse job = client.getFirewallClient() + .createPortForwardingRuleForVirtualMachine(ip.getId(), PortForwardingRule.Protocol.TCP, 22, vm.getId(), 22); assertTrue(jobComplete.apply(job.getJobId())); - rule = findRuleWithId(job.getId()); + portForwardingRule = client.getFirewallClient().getPortForwardingRule(job.getId()); + } catch (IllegalStateException e) { + Logger.CONSOLE.error("Failed while trying to allocate ip: " + e); // very likely an ip conflict, so retry; } } - assertEquals(rule.getIPAddressId(), ip.getId()); - assertEquals(rule.getVirtualMachineId(), vm.getId()); - assertEquals(rule.getPublicPort(), 22); - assertEquals(rule.getProtocol(), "tcp"); - checkRule(rule); + assertEquals(portForwardingRule.getIPAddressId(), ip.getId()); + assertEquals(portForwardingRule.getVirtualMachineId(), vm.getId()); + assertEquals(portForwardingRule.getPublicPort(), 22); + assertEquals(portForwardingRule.getProtocol(), "tcp"); + + checkPortForwardingRule(portForwardingRule); checkSSH(new IPSocket(ip.getIPAddress(), 22)); } + @Test(dependsOnMethods = "testCreatePortForwardingRule") + public void testListPortForwardingRules() throws Exception { + Set response = client.getFirewallClient().listPortForwardingRules(); + assert null != response; + assertTrue(response.size() >= 0); + for (final PortForwardingRule rule : response) { + checkPortForwardingRule(rule); + } + } + + @Test(dependsOnMethods = "testCreatePortForwardingRule") + public void testCreateFirewallRule() { + if (networksDisabled) + return; + + AsyncCreateResponse job = client.getFirewallClient().createFirewallRuleForIpAndProtocol( + ip.getId(), FirewallRule.Protocol.TCP, CreateFirewallRuleOptions.Builder.startPort(30).endPort(35)); + assertTrue(jobComplete.apply(job.getJobId())); + firewallRule = client.getFirewallClient().getFirewallRule(job.getId()); + + assertEquals(firewallRule.getStartPort(), 30); + assertEquals(firewallRule.getEndPort(), 35); + assertEquals(firewallRule.getProtocol(), FirewallRule.Protocol.TCP); + + checkFirewallRule(firewallRule); + } + + @Test(dependsOnMethods = "testCreateFirewallRule") + public void testListFirewallRules() { + Set rules = client.getFirewallClient().listFirewallRules(); + + assert rules != null; + assertTrue(rules.size() > 0); + + for(FirewallRule rule : rules) { + checkFirewallRule(rule); + } + } + @AfterGroups(groups = "live") protected void tearDown() { - if (rule != null) { - client.getFirewallClient().deletePortForwardingRule(rule.getId()); + if (firewallRule != null) { + client.getFirewallClient().deleteFirewallRule(firewallRule.getId()); + } + if (portForwardingRule != null) { + client.getFirewallClient().deletePortForwardingRule(portForwardingRule.getId()); } if (vm != null) { jobComplete.apply(client.getVirtualMachineClient().destroyVirtualMachine(vm.getId())); @@ -105,30 +171,18 @@ public class FirewallClientLiveTest extends BaseCloudStackClientLiveTest { super.tearDown(); } - public void testListPortForwardingRules() throws Exception { - Set response = client.getFirewallClient().listPortForwardingRules(); - assert null != response; - assertTrue(response.size() >= 0); - for (final PortForwardingRule rule : response) { - PortForwardingRule newDetails = findRuleWithId(rule.getId()); - assertEquals(rule.getId(), newDetails.getId()); - checkRule(rule); - } + protected void checkFirewallRule(FirewallRule rule) { + assertEquals(rule, + client.getFirewallClient().getFirewallRule(rule.getId())); + assert rule.getId() > 0 : rule; + assert rule.getStartPort() > 0 : rule; + assert rule.getEndPort() >= rule.getStartPort() : rule; + assert rule.getProtocol() != null; } - private PortForwardingRule findRuleWithId(final long id) { - return find(client.getFirewallClient().listPortForwardingRules(), new Predicate() { - - @Override - public boolean apply(PortForwardingRule arg0) { - return arg0.getId() == id; - } - - }); - } - - protected void checkRule(PortForwardingRule rule) { - assertEquals(rule.getId(), findRuleWithId(rule.getId()).getId()); + protected void checkPortForwardingRule(PortForwardingRule rule) { + assertEquals(rule, + client.getFirewallClient().getPortForwardingRule(rule.getId())); assert rule.getId() > 0 : rule; assert rule.getIPAddress() != null : rule; assert rule.getIPAddressId() > 0 : rule; diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java index 66a402027d..595e8f9d2f 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/options/ListPortForwardingRulesOptionsTest.java @@ -18,9 +18,9 @@ */ package org.jclouds.cloudstack.options; -import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.IPAddressId; import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.accountInDomain; import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.domainId; +import static org.jclouds.cloudstack.options.ListPortForwardingRulesOptions.Builder.ipAddressId; import static org.testng.Assert.assertEquals; import org.testng.annotations.Test; @@ -48,12 +48,12 @@ public class ListPortForwardingRulesOptionsTest { } public void testName() { - ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions().IPAddressId(9); + ListPortForwardingRulesOptions options = new ListPortForwardingRulesOptions().ipAddressId(9); assertEquals(ImmutableList.of("9"), options.buildQueryParameters().get("ipaddressid")); } public void testNameStatic() { - ListPortForwardingRulesOptions options = IPAddressId(9); + ListPortForwardingRulesOptions options = ipAddressId(9); assertEquals(ImmutableList.of("9"), options.buildQueryParameters().get("ipaddressid")); } diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java new file mode 100644 index 0000000000..1a67ca39c6 --- /dev/null +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListFirewallRulesResponseTest.java @@ -0,0 +1,72 @@ +/** + * 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.cloudstack.parse; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.jclouds.cloudstack.config.CloudStackParserModule; +import org.jclouds.cloudstack.domain.FirewallRule; +import org.jclouds.json.BaseSetParserTest; +import org.jclouds.json.config.GsonModule; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import java.util.Set; + +/** + * + * @author Andrei Savu + */ +@Test(groups = "unit") +public class ListFirewallRulesResponseTest extends BaseSetParserTest { + + @Override + protected Injector injector() { + return Guice.createInjector(new CloudStackParserModule(), new GsonModule() { + + @Override + protected void configure() { + bind(DateAdapter.class).to(Iso8601DateAdapter.class); + super.configure(); + } + + }); + } + + @Override + public String resource() { + return "/listfirewallrulesresponse.json"; + } + + @Override + @SelectJson("firewallrule") + public Set expected() { + Set CIDRs = ImmutableSet.of("0.0.0.0/0"); + return ImmutableSet.of( + FirewallRule.builder().id(2017).protocol(FirewallRule.Protocol.TCP).startPort(30) + .endPort(35).ipAddressId(2).ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE).CIDRs(CIDRs).build(), + FirewallRule.builder().id(2016).protocol(FirewallRule.Protocol.TCP).startPort(22) + .endPort(22).ipAddressId(2).ipAddress("10.27.27.51").state(FirewallRule.State.ACTIVE).CIDRs(CIDRs).build(), + FirewallRule.builder().id(10).protocol(FirewallRule.Protocol.TCP).startPort(22) + .endPort(22).ipAddressId(8).ipAddress("10.27.27.57").state(FirewallRule.State.ACTIVE).CIDRs(CIDRs).build() + ); + } + +} diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java index 85b41e656c..5079c7c6a5 100644 --- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java +++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListPortForwardingRulesResponseTest.java @@ -61,10 +61,12 @@ public class ListPortForwardingRulesResponseTest extends BaseSetParserTest expected() { Set cidrs = ImmutableSet.of("0.0.0.0/1", "128.0.0.0/1"); return ImmutableSet. of( - PortForwardingRule.builder().id(15).privatePort(22).protocol("tcp").publicPort(2022).virtualMachineId(3) - .virtualMachineName("i-3-3-VM").IPAddressId(3).IPAddress("72.52.126.32").state("Active").CIDRs(cidrs).build(), - PortForwardingRule.builder().id(18).privatePort(22).protocol("tcp").publicPort(22).virtualMachineId(89) - .virtualMachineName("i-3-89-VM").IPAddressId(34).IPAddress("72.52.126.63").state("Active").build()); + PortForwardingRule.builder().id(15).privatePort(22).protocol(PortForwardingRule.Protocol.TCP) + .publicPort(2022).virtualMachineId(3).virtualMachineName("i-3-3-VM").IPAddressId(3) + .IPAddress("72.52.126.32").state(PortForwardingRule.State.ACTIVE).CIDRs(cidrs).build(), + PortForwardingRule.builder().id(18).privatePort(22).protocol(PortForwardingRule.Protocol.TCP) + .publicPort(22).virtualMachineId(89).virtualMachineName("i-3-89-VM").IPAddressId(34) + .IPAddress("72.52.126.63").state(PortForwardingRule.State.ACTIVE).build()); } } diff --git a/apis/cloudstack/src/test/resources/createfirewallrulesresponse.json b/apis/cloudstack/src/test/resources/createfirewallrulesresponse.json new file mode 100644 index 0000000000..f6a727b408 --- /dev/null +++ b/apis/cloudstack/src/test/resources/createfirewallrulesresponse.json @@ -0,0 +1 @@ +{ "createfirewallruleresponse" : {"jobid":2036,"id":2017} } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/createportforwardingrulesresponse.json b/apis/cloudstack/src/test/resources/createportforwardingrulesresponse.json new file mode 100644 index 0000000000..cf29e1cbe3 --- /dev/null +++ b/apis/cloudstack/src/test/resources/createportforwardingrulesresponse.json @@ -0,0 +1 @@ +{ "createportforwardingruleresponse" : {"jobid":2035,"id":2015} } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/deletefirewallrulesresponse.json b/apis/cloudstack/src/test/resources/deletefirewallrulesresponse.json new file mode 100644 index 0000000000..abf5b6da0a --- /dev/null +++ b/apis/cloudstack/src/test/resources/deletefirewallrulesresponse.json @@ -0,0 +1 @@ +{ "deletefirewallruleresponse" : {"jobid":2037} } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/deleteportforwardingrulesresponse.json b/apis/cloudstack/src/test/resources/deleteportforwardingrulesresponse.json new file mode 100644 index 0000000000..552ad94410 --- /dev/null +++ b/apis/cloudstack/src/test/resources/deleteportforwardingrulesresponse.json @@ -0,0 +1 @@ +{ "deleteportforwardingruleresponse" : {"jobid":2038} } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/getfirewallrulesresponse.json b/apis/cloudstack/src/test/resources/getfirewallrulesresponse.json new file mode 100644 index 0000000000..88d3d47990 --- /dev/null +++ b/apis/cloudstack/src/test/resources/getfirewallrulesresponse.json @@ -0,0 +1,2 @@ +{ "listfirewallrulesresponse" : { "count":1 ,"firewallrule" : [ + {"id":2017,"protocol":"tcp","startport":"30","endport":"35","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0"} ] } } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json b/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json new file mode 100644 index 0000000000..3ea044d8fe --- /dev/null +++ b/apis/cloudstack/src/test/resources/getportforwardingrulesresponse.json @@ -0,0 +1,2 @@ +{ "listportforwardingrulesresponse" : { "portforwardingrule" : [ + {"id":15,"privateport":"22","protocol":"tcp","publicport":"2022","virtualmachineid":3,"virtualmachinename":"i-3-3-VM","ipaddressid":3,"ipaddress":"72.52.126.32","state":"Active","cidrlist":"0.0.0.0/1,128.0.0.0/1"} ] } } \ No newline at end of file diff --git a/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json b/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json new file mode 100644 index 0000000000..e93d76e4cb --- /dev/null +++ b/apis/cloudstack/src/test/resources/listfirewallrulesresponse.json @@ -0,0 +1,4 @@ +{ "listfirewallrulesresponse" : { "count":3 ,"firewallrule" : [ + {"id":2017,"protocol":"tcp","startport":"30","endport":"35","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0"}, + {"id":2016,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":2,"ipaddress":"10.27.27.51","state":"Active","cidrlist":"0.0.0.0/0"}, + {"id":10,"protocol":"tcp","startport":"22","endport":"22","ipaddressid":8,"ipaddress":"10.27.27.57","state":"Active","cidrlist":"0.0.0.0/0"} ] } } \ No newline at end of file