From 39d7a96d49bb34d29592e56a87405b5f86d05fce Mon Sep 17 00:00:00 2001 From: Zack Shoylev Date: Fri, 15 Aug 2014 16:17:39 -0500 Subject: [PATCH] Adds support for the Security Group extension to neutron --- .../openstack/neutron/v2/NeutronApi.java | 10 + .../neutron/v2/domain/AddressPair.java | 11 +- .../openstack/neutron/v2/domain/Rule.java | 375 ++++++++++ .../neutron/v2/domain/RuleDirection.java | 61 ++ .../neutron/v2/domain/RuleEthertype.java | 61 ++ .../neutron/v2/domain/RuleProtocol.java | 65 ++ .../openstack/neutron/v2/domain/Rules.java | 35 + .../neutron/v2/domain/SecurityGroup.java | 219 ++++++ .../neutron/v2/domain/SecurityGroups.java | 36 + .../v2/extensions/SecurityGroupApi.java | 186 +++++ .../v2/fallbacks/EmptyRulesFallback.java | 45 ++ .../EmptySecurityGroupsFallback.java | 45 ++ .../neutron/v2/functions/ParseRules.java | 38 + .../v2/functions/ParseSecurityGroups.java | 38 + .../v2/functions/RulesToPagedIterable.java | 66 ++ .../SecurityGroupsToPagedIterable.java | 66 ++ .../extensions/SecurityGroupApiLiveTest.java | 88 +++ .../extensions/SecurityGroupApiMockTest.java | 655 ++++++++++++++++++ .../neutron/v2/features/PortApiMockTest.java | 4 +- .../security_group_create_request.json | 6 + .../security_group_create_response.json | 34 + .../security_group_get_response.json | 58 ++ .../security_group_list_response.json | 116 ++++ .../security_group_list_response_paged1.json | 126 ++++ .../security_group_list_response_paged2.json | 122 ++++ .../security_group_rule_create_request.json | 11 + .../security_group_rule_create_response.json | 15 + .../security_group_rule_get_response.json | 14 + .../security_group_rule_list_response.json | 52 ++ ...urity_group_rule_list_response_paged1.json | 62 ++ ...urity_group_rule_list_response_paged2.json | 58 ++ 31 files changed, 2766 insertions(+), 12 deletions(-) create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rule.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleDirection.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleEthertype.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleProtocol.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rules.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroup.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroups.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApi.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRulesFallback.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySecurityGroupsFallback.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRules.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSecurityGroups.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RulesToPagedIterable.java create mode 100644 apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SecurityGroupsToPagedIterable.java create mode 100644 apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiLiveTest.java create mode 100644 apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiMockTest.java create mode 100644 apis/openstack-neutron/src/test/resources/security_group_create_request.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_create_response.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_get_response.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_list_response.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_list_response_paged1.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_list_response_paged2.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_rule_create_request.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_rule_create_response.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_rule_get_response.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_rule_list_response.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged1.json create mode 100644 apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged2.json diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java index 233c41b389..358e38fb17 100644 --- a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java @@ -25,6 +25,7 @@ import org.jclouds.Constants; import org.jclouds.location.Region; import org.jclouds.location.functions.RegionToEndpoint; import org.jclouds.openstack.neutron.v2.extensions.RouterApi; +import org.jclouds.openstack.neutron.v2.extensions.SecurityGroupApi; import org.jclouds.openstack.neutron.v2.features.NetworkApi; import org.jclouds.openstack.neutron.v2.features.PortApi; import org.jclouds.openstack.neutron.v2.features.SubnetApi; @@ -89,4 +90,13 @@ public interface NeutronApi extends Closeable { @Delegate Optional getRouterExtensionApi(@EndpointParam(parser = RegionToEndpoint.class) String region); + /** + * Provides access to SecurityGroup features. + * + *

NOTE

+ * This API is an extension that may or may not be present in your OpenStack cloud. Use the Optional return type + * to determine if it is present. + */ + @Delegate + Optional getSecurityGroupApi(@EndpointParam(parser = RegionToEndpoint.class) String region); } diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java index 4e317cee11..a222908f88 100644 --- a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java @@ -101,19 +101,10 @@ public class AddressPair { * In this case, both parameters are required. * @return the Builder for AddressPair */ - public static Builder createOptions(String macAddress, String ipAddress) { + public static Builder builder(String macAddress, String ipAddress) { return new Builder(macAddress, ipAddress); } - /** - * Returns a builder, but requires the user to specify any parameters required when updating a resource. - * In this case, there are none. - * @return the Builder for AddressPair - */ - public static Builder updateOptions() { - return new Builder(); - } - /** * Gets a Builder configured as this object. */ diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rule.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rule.java new file mode 100644 index 0000000000..e3b7aca259 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rule.java @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.domain; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import java.beans.ConstructorProperties; +import javax.inject.Named; + +import org.jclouds.javax.annotation.Nullable; +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; + +/** + * Contains a mapping between a MAC address and an IP address. + */ +public class Rule { + + private String id; + @Named("tenant_id") + private String tenantId; + private RuleDirection direction; + @Named("security_group_id") + private String securityGroupId; + private RuleEthertype ethertype; + @Named("port_range_min") + private Integer portRangeMin; + @Named("port_range_max") + private Integer portRangeMax; + private RuleProtocol protocol; + @Named("remote_group_id") + private String remoteGroupId; + @Named("remote_ip_prefix") + private String remoteIpPrefix; + + @ConstructorProperties({"id", "tenant_id", "direction", "security_group_id", "ethertype", "port_range_min", + "port_range_max", "protocol", "remote_group_id", "remote_ip_prefix"}) + protected Rule(String id, String tenantId, RuleDirection direction, String securityGroupId, + RuleEthertype ethertype, Integer portRangeMin, Integer portRangeMax, + RuleProtocol protocol, String remoteGroupId, String remoteIpPrefix) { + this.id = id; + this.tenantId = tenantId; + this.direction = direction; + this.securityGroupId = securityGroupId; + this.ethertype = ethertype; + this.portRangeMin = portRangeMin; + this.portRangeMax = portRangeMax; + this.protocol = protocol; + this.remoteGroupId = remoteGroupId; + this.remoteIpPrefix = remoteIpPrefix; + } + + private Rule(Rule rule) { + this(rule.id, + rule.tenantId, + rule.direction, + rule.securityGroupId, + rule.ethertype, + rule.portRangeMin, + rule.portRangeMax, + rule.protocol, + rule.remoteGroupId, + rule.remoteIpPrefix + ); + } + + private Rule() {} + + /** + * @return The identifier for this rule. + */ + @Nullable + public String getId() { + return id; + } + + /** + * @return The identifier of the tenant for this rule. + */ + @Nullable + public String getTenantId() { + return tenantId; + } + + /** + * @return The direction in which the security group rule is applied. + */ + @Nullable + public RuleDirection getDirection() { + return direction; + } + + /** + * @return The security group ID to associate with this security group rule. + */ + @Nullable + public String getSecurityGroupId() { + return securityGroupId; + } + + /** + * @return The internet protocol version type of this rule. + */ + @Nullable + public RuleEthertype getEthertype() { + return ethertype; + } + + /** + * @return The minimum port number in the range that is matched by the security group rule. If the protocol is TCP + * or UDP, this value must be less than or equal to the value of the port_range_max attribute. If the protocol is + * ICMP, this value must be an ICMP type. + */ + @Nullable + public Integer getPortRangeMin() { + return portRangeMin; + } + + /** + * @return The maximum port number in the range that is matched by the security group rule. The port_range_min + * attribute constrains the port_range_max attribute. If the protocol is ICMP, this value must be an ICMP type. + */ + @Nullable + public Integer getPortRangeMax() { + return portRangeMax; + } + + /** + * @return The protocol that is matched by the security group rule. Valid values are null, tcp, udp, and icmp. + */ + @Nullable + public RuleProtocol getProtocol() { + return protocol; + } + + /** + * @return The remote group ID to be associated with this security group rule. + */ + @Nullable + public String getRemoteGroupId() { + return remoteGroupId; + } + + /** + * @return The remote IP prefix to be associated with this security group rule. This attribute matches the specified + * IP prefix as the source IP address of the IP packet. + */ + @Nullable + public String getRemoteIpPrefix() { + return remoteIpPrefix; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Rule that = (Rule) o; + + return Objects.equal(this.id, that.id) && + Objects.equal(this.tenantId, that.tenantId) && + Objects.equal(this.direction, that.direction) && + Objects.equal(this.securityGroupId, that.securityGroupId) && + Objects.equal(this.ethertype, that.ethertype) && + Objects.equal(this.portRangeMin, that.portRangeMin) && + Objects.equal(this.portRangeMax, that.portRangeMax) && + Objects.equal(this.protocol, that.protocol) && + Objects.equal(this.remoteGroupId, that.remoteGroupId) && + Objects.equal(this.remoteIpPrefix, that.remoteIpPrefix); + } + + @Override + public int hashCode() { + return Objects.hashCode(id, tenantId, direction, securityGroupId, ethertype, portRangeMin, + portRangeMax, protocol, remoteGroupId, remoteIpPrefix); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id) + .add("tenantId", tenantId) + .add("direction", direction) + .add("securityGroupId", securityGroupId) + .add("ethertype", ethertype) + .add("portRangeMin", portRangeMin) + .add("portRangeMax", portRangeMax) + .add("protocol", protocol) + .add("remoteGroupId", remoteGroupId) + .add("remoteIpPrefix", remoteIpPrefix) + .toString(); + } + + + /* + * Methods to get the Create and Update builders follow + */ + + /** + * @return the Builder for creating a new SecurityGroupRule + */ + public static CreateBuilder createOptions(RuleDirection direction, String securityGroupId) { + return new CreateBuilder(direction, securityGroupId); + } + + public abstract static class Builder { + // Keep track of the builder's state. + protected Rule rule; + + private Builder() { + rule = new Rule(); + } + + protected abstract ParameterizedBuilderType self(); + + /** + * The tenant id for this rule. Usually can only be specified by administrators. + * + * @return the Builder. + * @see Rule#getTenantId() + */ + public ParameterizedBuilderType tenantId(String tenantId) { + rule.tenantId = tenantId; + return self(); + } + + /** + * The direction in which the security group rule is applied. + * + * @return the Builder. + * @see Rule#getDirection() + */ + public ParameterizedBuilderType direction(RuleDirection direction) { + rule.direction = direction; + return self(); + } + + /** + * The security group ID to associate with this security group rule. + * + * @return the Builder. + * @see Rule#getSecurityGroupId() + */ + public ParameterizedBuilderType securityGroupId(String securityGroupId) { + rule.securityGroupId = securityGroupId; + return self(); + } + + /** + * The internet protocol version for this rule. + * + * @return the Builder. + * @see Rule#getEthertype() + */ + public ParameterizedBuilderType ethertype(RuleEthertype ethertype) { + rule.ethertype = ethertype; + return self(); + } + + /** + * The minimum port number in the range that is matched by the security group rule. + * + * @return the Builder. + * @see Rule#getPortRangeMin() + */ + public ParameterizedBuilderType portRangeMin(Integer portRangeMin) { + rule.portRangeMin = portRangeMin; + return self(); + } + + /** + * The maximum port number in the range that is matched by the security group rule. + * + * @return the Builder. + * @see Rule#getPortRangeMax() + */ + public ParameterizedBuilderType portRangeMax(Integer portRangeMax) { + rule.portRangeMax = portRangeMax; + return self(); + } + + /** + * The protocol that is matched by the security group rule. Valid values are null, tcp, udp, and icmp. + * + * @return the Builder. + * @see Rule#getProtocol() + */ + public ParameterizedBuilderType protocol(RuleProtocol protocol) { + rule.protocol = protocol; + return self(); + } + + /** + * The remote group ID to be associated with this security group rule. You can specify either remote_group_id or + * remote_ip_prefix in the request body. + * + * @return the Builder. + * @see Rule#getRemoteGroupId() + */ + public ParameterizedBuilderType remoteGroupId(String remoteGroupId) { + rule.remoteGroupId = remoteGroupId; + return self(); + } + + /** + * The remote IP prefix to be associated with this security group rule. You can specify either remote_group_id + * or remote_ip_prefix in the request body. This attribute matches the specified IP prefix as the source IP + * address of the IP packet. + * + * @return the Builder. + * @see Rule#getRemoteIpPrefix() + */ + public ParameterizedBuilderType remoteIpPrefix(String remoteIpPrefix) { + rule.remoteIpPrefix = remoteIpPrefix; + return self(); + } + } + + /** + * This is used to build a CreateOptions object. + */ + public static class CreateBuilder extends Builder { + /** + * Supply required properties for creating a Builder + */ + private CreateBuilder(RuleDirection direction, String securityGroupId) { + rule.direction = direction; + rule.securityGroupId = securityGroupId; + } + + /** + * @return a CreateOptions constructed with this Builder. + */ + public CreateOptions build() { + return new CreateOptions(rule); + } + + protected CreateBuilder self() { + return this; + } + } + + /** + * Create and Update options - extend the domain class, passed to API update and create calls. + * Essentially the same as the domain class. Ensure validation and safe typing. + */ + public static class CreateOptions extends Rule { + private CreateOptions(Rule rule) { + super(rule); + checkNotNull(rule.getDirection(), "direction should not be null"); + checkNotNull(rule.getSecurityGroupId(), "security group id should not be null"); + checkState(rule.getPortRangeMax()>= rule.getPortRangeMin(), + "port range max should be greater than or equal to port range min"); + checkState(rule.getRemoteGroupId()==null || rule.getRemoteIpPrefix()==null, + "You can specify either remote_group_id or remote_ip_prefix in the request body."); + } + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleDirection.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleDirection.java new file mode 100644 index 0000000000..759bb8c1f9 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleDirection.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jclouds.openstack.neutron.v2.domain; + +/** + * The direction in which the security group rule is applied. + */ +public enum RuleDirection { + /** + * For a compute instance, an ‘ingress’ security group rule matches traffic that is incoming (ingress) for that instance. + */ + INGRESS("ingress"), + /** + * An ‘egress’ rule is applied to traffic leaving the instance. + */ + EGRESS("egress"), + /** + * Used by jclouds when the service returns an unknown value other than null. + */ + UNRECOGNIZED("unrecognized"); + + private String name; + + private RuleDirection(String name) { + this.name = name; + } + + public String toString() { + return name; + } + + /** + * This provides GSON enum support in jclouds. + * */ + public static RuleDirection fromValue(String name){ + if (name != null) { + for (RuleDirection value : RuleDirection.values()) { + if (name.equalsIgnoreCase(value.name)) { + return value; + } + } + return UNRECOGNIZED; + } + return null; + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleEthertype.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleEthertype.java new file mode 100644 index 0000000000..150807001d --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleEthertype.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jclouds.openstack.neutron.v2.domain; + +/** + * The direction in which the security group rule is applied. + */ +public enum RuleEthertype { + /** + * Internet Protocol version 4 + */ + IPV4("IPv4"), + /** + * Internet Protocol version 6 + */ + IPV6("IPv6"), + /** + * Used by jclouds when the service returns an unknown value other than null. + */ + UNRECOGNIZED("unrecognized"); + + private String name; + + private RuleEthertype(String name) { + this.name = name; + } + + public String toString() { + return name; + } + + /** + * This provides GSON enum support in jclouds. + * */ + public static RuleEthertype fromValue(String name){ + if (name != null) { + for (RuleEthertype value : RuleEthertype.values()) { + if (name.equalsIgnoreCase(value.name)) { + return value; + } + } + return UNRECOGNIZED; + } + return null; + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleProtocol.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleProtocol.java new file mode 100644 index 0000000000..9ad105f3a7 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleProtocol.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jclouds.openstack.neutron.v2.domain; + +/** + * The protocol that is matched by the security group rule. Valid values are null, tcp, udp, and icmp. + */ +public enum RuleProtocol { + /** + * Transmission Control Protocol + */ + TCP("tcp"), + /** + * User Datagram Protocol + */ + UDP("udp"), + /** + * Internet Control Message Protocol + */ + ICMP("icmp"), + /** + * Used by jclouds when the service returns an unknown value other than null. + */ + UNRECOGNIZED("unrecognized"); + + private String name; + + private RuleProtocol(String name) { + this.name = name; + } + + public String toString() { + return name; + } + + /** + * This provides GSON enum support in jclouds. + * */ + public static RuleProtocol fromValue(String name){ + if (name != null) { + for (RuleProtocol value : RuleProtocol.values()) { + if (name.equalsIgnoreCase(value.name)) { + return value; + } + } + return UNRECOGNIZED; + } + return null; + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rules.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rules.java new file mode 100644 index 0000000000..4794a189ed --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rules.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.domain; + +import java.beans.ConstructorProperties; + +import org.jclouds.openstack.v2_0.domain.Link; +import org.jclouds.openstack.v2_0.domain.PaginatedCollection; +import com.google.common.collect.ImmutableSet; + +/** + * A collection of Networks + */ +public class Rules extends PaginatedCollection { + public static final Rules EMPTY = new Rules(ImmutableSet. of(), ImmutableSet. of()); + + @ConstructorProperties({"security_group_rules", "security_group_rules_links"}) + protected Rules(Iterable securityGroups, Iterable securityGroupRulesLinks) { + super(securityGroups, securityGroupRulesLinks); + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroup.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroup.java new file mode 100644 index 0000000000..604776eef0 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroup.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.domain; + +import java.beans.ConstructorProperties; + +import javax.inject.Named; +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; + +/** + * Contains a mapping between a MAC address and an IP address. + */ +public class SecurityGroup { + + private String id; + @Named("tenant_id") + private String tenantId; + private String name; + private String description; + @Named("security_group_rules") + private ImmutableList rules; + + @ConstructorProperties({"id", "tenant_id", "name", "description", "security_group_rules"}) + protected SecurityGroup(String id, String tenantId, String name, String description, + ImmutableList rules) { + this.id = id; + this.tenantId = tenantId; + this.name = name; + this.description = description; + this.rules = rules; + } + + private SecurityGroup(SecurityGroup securityGroup) { + this(securityGroup.id, + securityGroup.tenantId, + securityGroup.name, + securityGroup.description, + securityGroup.rules + ); + } + + private SecurityGroup() {} + + /** + * @return The identifier for this Security Group. + */ + @Nullable + public String getId() { + return id; + } + + /** + * @return The identifier of the tenant for this Security Group. + */ + @Nullable + public String getTenantId() { + return tenantId; + } + + /** + * @return The name of the Security Group. + */ + @Nullable + public String getName() { + return name; + } + + /** + * @return The description of the Security Group. + */ + @Nullable + public String getDescription() { + return description; + } + + /** + * @return The collection of rules for this Security Group. + */ + public ImmutableList getRules() { + return rules!=null ? rules : ImmutableList.of(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + SecurityGroup that = (SecurityGroup) o; + + return Objects.equal(this.id, that.id) && + Objects.equal(this.tenantId, that.tenantId) && + Objects.equal(this.name, that.name) && + Objects.equal(this.description, that.description) && + Objects.equal(this.rules, that.rules); + } + + @Override + public int hashCode() { + return Objects.hashCode(id, tenantId, name, description, rules); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id) + .add("tenantId", tenantId) + .add("name", name) + .add("description", description) + .add("securityGroupRules", rules) + .toString(); + } + + /* + * Methods to get the Create and Update builders follow + */ + + /** + * @return the Builder for creating a new SecurityGroup + */ + public static CreateBuilder createOptions() { + return new CreateBuilder(); + } + + private abstract static class Builder { + // Keep track of the builder's state. + protected SecurityGroup securityGroup; + + private Builder() { + securityGroup = new SecurityGroup(); + } + + protected abstract ParameterizedBuilderType self(); + + /** + * The tenant id for this Security Group. Usually can only be specified by administrators. + * + * @return the Builder. + * @see SecurityGroup#getTenantId() + */ + public ParameterizedBuilderType tenantId(String tenantId) { + securityGroup.tenantId = tenantId; + return self(); + } + + /** + * The name for this Security Group. + * + * @return the Builder. + * @see SecurityGroup#getName() + */ + public ParameterizedBuilderType name(String name) { + securityGroup.name = name; + return self(); + } + + /** + * The description for this Security Group. + * + * @return the Builder. + * @see SecurityGroup#getDescription() + */ + public ParameterizedBuilderType description(String description) { + securityGroup.description = description; + return self(); + } + } + + /** + * Create and Update builders (inheriting from Builder) + */ + public static class CreateBuilder extends Builder { + /** + * Supply required properties for creating a Builder + */ + private CreateBuilder() { + } + + /** + * @return a CreateOptions constructed with this Builder. + */ + public CreateOptions build() { + return new CreateOptions(securityGroup); + } + + protected CreateBuilder self() { + return this; + } + } + + /** + * Create and Update options - extend the domain class, passed to API update and create calls. + * Essentially the same as the domain class. Ensure validation and safe typing. + */ + public static class CreateOptions extends SecurityGroup { + private CreateOptions(SecurityGroup securityGroup) { + super(securityGroup); + } + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroups.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroups.java new file mode 100644 index 0000000000..044ce1c783 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroups.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.domain; + +import java.beans.ConstructorProperties; + +import org.jclouds.openstack.v2_0.domain.Link; +import org.jclouds.openstack.v2_0.domain.PaginatedCollection; + +import com.google.common.collect.ImmutableSet; + +/** + * A collection of Networks + */ +public class SecurityGroups extends PaginatedCollection { + public static final SecurityGroups EMPTY = new SecurityGroups(ImmutableSet. of(), ImmutableSet. of()); + + @ConstructorProperties({"security_groups", "security_groups_links"}) + protected SecurityGroups(Iterable securityGroups, Iterable securityGroupsLinks) { + super(securityGroups, securityGroupsLinks); + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApi.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApi.java new file mode 100644 index 0000000000..4c0b4da4b9 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApi.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.extensions; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks; +import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404; +import org.jclouds.collect.PagedIterable; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; +import org.jclouds.openstack.neutron.v2.domain.Rule; +import org.jclouds.openstack.neutron.v2.domain.Rules; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroup; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroups; +import org.jclouds.openstack.neutron.v2.fallbacks.EmptyRulesFallback; +import org.jclouds.openstack.neutron.v2.fallbacks.EmptySecurityGroupsFallback; +import org.jclouds.openstack.neutron.v2.functions.ParseRules; +import org.jclouds.openstack.neutron.v2.functions.ParseSecurityGroups; +import org.jclouds.openstack.neutron.v2.functions.RulesToPagedIterable; +import org.jclouds.openstack.neutron.v2.functions.SecurityGroupsToPagedIterable; +import org.jclouds.openstack.v2_0.options.PaginationOptions; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.ResponseParser; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.annotations.WrapWith; +import com.google.common.annotations.Beta; + +/** + * Provides access to Security Group extension operations for the OpenStack Networking (Neutron) v2 API. + *

+ * Security groups and security group rules allows administrators and tenants the ability to specify the type of + * traffic and direction (ingress/egress) that is allowed to pass through a port. A security group is a container for + * security group rules. + */ +@Beta +@RequestFilters(AuthenticateRequest.class) +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface SecurityGroupApi { + /** + * Groups + */ + + /** + * @return all security groups currently defined in Neutron for the current tenant. + */ + @Path("/security-groups") + @Named("security-group:list") + @GET + @ResponseParser(ParseSecurityGroups.class) + @Transform(SecurityGroupsToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listSecurityGroups(); + + /** + * @return all security groups currently defined in Neutron for the current tenant. + */ + @Path("/security-groups") + @Named("security-group:list") + @GET + @ResponseParser(ParseSecurityGroups.class) + @Fallback(EmptySecurityGroupsFallback.class) + SecurityGroups listSecurityGroups(PaginationOptions options); + + /** + * @param id the id of the security group to return + * @return SecurityGroup or null if not found. + */ + @Path("/security-groups/{id}") + @Named("security-group:get") + @GET + @SelectJson("security_group") + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + @Nullable + SecurityGroup getSecurityGroup(@PathParam("id") String id); + + /** + * Create a new SecurityGroup. + * + * @param securityGroup Describes the security group to be created. + * @return a reference of the newly-created security group + */ + @Path("/security-groups") + @Named("secuity-group:create") + @POST + @SelectJson("security_group") + SecurityGroup create(@WrapWith("security_group") SecurityGroup.CreateOptions securityGroup); + + /** + * Deletes the specified Security Group. + * + * @param id the id of the security group to delete + * @return true if delete was successful, false if not + */ + @Path("/security-groups/{id}") + @Named("security-group:delete") + @DELETE + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean deleteSecurityGroup(@PathParam("id") String id); + + /** + * Rules + */ + + /** + * @return all security groups rules currently defined in Neutron for the current tenant. + */ + @Path("/security-group-rules") + @Named("security-group-rule:list") + @GET + @ResponseParser(ParseRules.class) + @Transform(RulesToPagedIterable.class) + @Fallback(EmptyPagedIterableOnNotFoundOr404.class) + PagedIterable listRules(); + + /** + * @return all security groups rules currently defined in Neutron for the current tenant. + */ + @Path("/security-group-rules") + @Named("security-group-rule:list") + @GET + @ResponseParser(ParseRules.class) + @Fallback(EmptyRulesFallback.class) + Rules listRules(PaginationOptions options); + + /** + * @param id the id of the security group rule to return. + * @return SecurityGroupRule or null if not found. + */ + @Path("/security-group-rules/{id}") + @Named("security-group-rule:get") + @GET + @SelectJson("security_group_rule") + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + @Nullable + Rule get(@PathParam("id") String id); + + /** + * Create a new Security Group Rule. + * + * @param securityGroupRule Describes the security group rule to be created. + * @return a reference of the newly-created security group rule. + */ + @Path("/security-group-rules") + @Named("security-group-rule:create") + @POST + @SelectJson("security_group_rule") + Rule create(@WrapWith("security_group_rule") Rule.CreateOptions securityGroupRule); + + /** + * Deletes the specified Security Group Rule. + * + * @param id the id of the security group rule to delete. + * @return true if delete was successful, false if not. + */ + @Path("/security-group-rules/{id}") + @Named("security-group-rule:delete") + @DELETE + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean deleteRule(@PathParam("id") String id); +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRulesFallback.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRulesFallback.java new file mode 100644 index 0000000000..a559f4fe99 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRulesFallback.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jclouds.openstack.neutron.v2.fallbacks; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; +import static com.google.common.util.concurrent.Futures.immediateFuture; +import static org.jclouds.http.HttpUtils.contains404; +import static org.jclouds.util.Throwables2.getFirstThrowableOfType; + +import org.jclouds.Fallback; +import org.jclouds.openstack.neutron.v2.domain.Rules; +import org.jclouds.rest.ResourceNotFoundException; +import com.google.common.util.concurrent.ListenableFuture; + +public class EmptyRulesFallback implements Fallback { + + public ListenableFuture create(Throwable t) throws Exception { + return immediateFuture(createOrPropagate(t)); + } + + @Override + public Rules createOrPropagate(Throwable t) throws Exception { + if ((getFirstThrowableOfType(checkNotNull(t, "throwable"), ResourceNotFoundException.class) != null) + || contains404(t)) { + return Rules.EMPTY; + } + throw propagate(t); + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySecurityGroupsFallback.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySecurityGroupsFallback.java new file mode 100644 index 0000000000..5343c3fdea --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySecurityGroupsFallback.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jclouds.openstack.neutron.v2.fallbacks; + +import com.google.common.util.concurrent.ListenableFuture; +import org.jclouds.Fallback; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroups; +import org.jclouds.rest.ResourceNotFoundException; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; +import static com.google.common.util.concurrent.Futures.immediateFuture; +import static org.jclouds.http.HttpUtils.contains404; +import static org.jclouds.util.Throwables2.getFirstThrowableOfType; + +public class EmptySecurityGroupsFallback implements Fallback { + + public ListenableFuture create(Throwable t) throws Exception { + return immediateFuture(createOrPropagate(t)); + } + + @Override + public SecurityGroups createOrPropagate(Throwable t) throws Exception { + if ((getFirstThrowableOfType(checkNotNull(t, "throwable"), ResourceNotFoundException.class) != null) + || contains404(t)) { + return SecurityGroups.EMPTY; + } + throw propagate(t); + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRules.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRules.java new file mode 100644 index 0000000000..954180b7e5 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRules.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.functions; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; +import org.jclouds.openstack.neutron.v2.domain.Rules; + +import com.google.inject.TypeLiteral; + +/** + * Used by jclouds to provide more specific collections and fallbacks. + */ +@Singleton +public class ParseRules extends ParseJson { + + @Inject + public ParseRules(Json json) { + super(json, TypeLiteral.get(Rules.class)); + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSecurityGroups.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSecurityGroups.java new file mode 100644 index 0000000000..fbc3fd49fb --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSecurityGroups.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.functions; + +import com.google.inject.TypeLiteral; +import org.jclouds.http.functions.ParseJson; +import org.jclouds.json.Json; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroup; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroups; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Used by jclouds to provide more specific collections and fallbacks. + */ +@Singleton +public class ParseSecurityGroups extends ParseJson { + + @Inject + public ParseSecurityGroups(Json json) { + super(json, TypeLiteral.get(SecurityGroups.class)); + } +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RulesToPagedIterable.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RulesToPagedIterable.java new file mode 100644 index 0000000000..d664cd6893 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RulesToPagedIterable.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.internal.Arg0ToPagedIterable; +import org.jclouds.openstack.neutron.v2.NeutronApi; +import org.jclouds.openstack.neutron.v2.domain.Rule; +import org.jclouds.openstack.neutron.v2.extensions.SecurityGroupApi; +import org.jclouds.openstack.v2_0.options.PaginationOptions; + +import com.google.common.base.Function; +import com.google.common.base.Optional; + +/** + * Ensures Routers works as PagedIterable. + */ +public class RulesToPagedIterable extends + Arg0ToPagedIterable.FromCaller { + + private final NeutronApi api; + + @Inject + protected RulesToPagedIterable(NeutronApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> markerToNextForArg0(Optional arg0) { + String region = arg0.isPresent() ? arg0.get().toString() : null; + final SecurityGroupApi securityGroupApi = api.getSecurityGroupApi(region).get(); + return new Function>() { + + @SuppressWarnings("unchecked") + @Override + public IterableWithMarker apply(Object input) { + PaginationOptions paginationOptions = PaginationOptions.class.cast(input); + return IterableWithMarker.class.cast(securityGroupApi.listRules(paginationOptions)); + } + + @Override + public String toString() { + return "listRules()"; + } + }; + } + +} diff --git a/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SecurityGroupsToPagedIterable.java b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SecurityGroupsToPagedIterable.java new file mode 100644 index 0000000000..15c7c14cf1 --- /dev/null +++ b/apis/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SecurityGroupsToPagedIterable.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.internal.Arg0ToPagedIterable; +import org.jclouds.openstack.neutron.v2.NeutronApi; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroup; +import org.jclouds.openstack.neutron.v2.extensions.SecurityGroupApi; +import org.jclouds.openstack.v2_0.options.PaginationOptions; + +import com.google.common.base.Function; +import com.google.common.base.Optional; + +/** + * Ensures Routers works as PagedIterable. + */ +public class SecurityGroupsToPagedIterable extends + Arg0ToPagedIterable.FromCaller { + + private final NeutronApi api; + + @Inject + protected SecurityGroupsToPagedIterable(NeutronApi api) { + this.api = checkNotNull(api, "api"); + } + + @Override + protected Function> markerToNextForArg0(Optional arg0) { + String region = arg0.isPresent() ? arg0.get().toString() : null; + final SecurityGroupApi securityGroupApi = api.getSecurityGroupApi(region).get(); + return new Function>() { + + @SuppressWarnings("unchecked") + @Override + public IterableWithMarker apply(Object input) { + PaginationOptions paginationOptions = PaginationOptions.class.cast(input); + return IterableWithMarker.class.cast(securityGroupApi.listSecurityGroups(paginationOptions)); + } + + @Override + public String toString() { + return "listSecurityGroups()"; + } + }; + } + +} diff --git a/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiLiveTest.java b/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiLiveTest.java new file mode 100644 index 0000000000..8771a3ebb4 --- /dev/null +++ b/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiLiveTest.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jclouds.openstack.neutron.v2.extensions; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.openstack.neutron.v2.domain.Rule; +import org.jclouds.openstack.neutron.v2.domain.RuleDirection; +import org.jclouds.openstack.neutron.v2.domain.RuleEthertype; +import org.jclouds.openstack.neutron.v2.domain.RuleProtocol; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroup; +import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiLiveTest; +import org.testng.annotations.Test; + +/** + * Tests parsing and Guice wiring of RouterApi + */ +@Test(groups = "live", testName = "SecurityGroupApiLiveTest") +public class SecurityGroupApiLiveTest extends BaseNeutronApiLiveTest { + + /** + * Smoke test for the Security Group extension for Neutron + */ + public void testCreateUpdateAndDeleteSecurityGroup() { + for (String region : api.getConfiguredRegions()) { + SecurityGroupApi sgApi = api.getSecurityGroupApi(region).get(); + + SecurityGroup securityGroup = sgApi.create( + SecurityGroup.createOptions().name("jclouds-test").description("jclouds test security group").build()); + assertNotNull(securityGroup); + + Rule rule = sgApi.create( + Rule.createOptions(RuleDirection.EGRESS, securityGroup.getId()) + .ethertype(RuleEthertype.IPV6) + .portRangeMax(90) + .portRangeMin(80) + .protocol(RuleProtocol.TCP) + .build()); + + assertNotNull(rule); + + // Refresh + securityGroup = sgApi.getSecurityGroup(securityGroup.getId()); + + assertEquals(securityGroup.getName(), "jclouds-test"); + assertEquals(securityGroup.getDescription(), "jclouds test security group"); + + assertEquals(securityGroup.getRules().size(), 3, "Expected 2 default rules"); + + Rule newSecGroupRule = null; + for(Rule sgr : securityGroup.getRules()) { + if(sgr.getId().equals(rule.getId())) { + newSecGroupRule = sgr; + break; + } + } + assertNotNull(newSecGroupRule, "Did not find the new rule in the group."); + + assertEquals(rule, newSecGroupRule); + + assertEquals(rule.getEthertype(), RuleEthertype.IPV6); + assertEquals(rule.getProtocol(), RuleProtocol.TCP); + assertEquals(rule.getPortRangeMax().intValue(), 90); + assertEquals(rule.getPortRangeMin().intValue(), 80); + assertEquals(rule.getDirection(), RuleDirection.EGRESS); + + assertTrue(sgApi.deleteRule(rule.getId())); + assertTrue(sgApi.deleteSecurityGroup(securityGroup.getId())); + } + } +} diff --git a/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiMockTest.java b/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiMockTest.java new file mode 100644 index 0000000000..c14544dbe8 --- /dev/null +++ b/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiMockTest.java @@ -0,0 +1,655 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.neutron.v2.extensions; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; + +import org.jclouds.openstack.neutron.v2.NeutronApi; +import org.jclouds.openstack.neutron.v2.domain.Rule; +import org.jclouds.openstack.neutron.v2.domain.RuleDirection; +import org.jclouds.openstack.neutron.v2.domain.RuleEthertype; +import org.jclouds.openstack.neutron.v2.domain.RuleProtocol; +import org.jclouds.openstack.neutron.v2.domain.Rules; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroup; +import org.jclouds.openstack.neutron.v2.domain.SecurityGroups; +import org.jclouds.openstack.neutron.v2.internal.BaseNeutronApiMockTest; +import org.jclouds.openstack.v2_0.options.PaginationOptions; +import org.jclouds.rest.ResourceNotFoundException; +import org.testng.annotations.Test; + +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; + +/** + * Tests NetworkApi Guice wiring and parsing + * + */ +@Test +public class SecurityGroupApiMockTest extends BaseNeutronApiMockTest { + + public void testCreateSecurityGroup() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(201).setBody(stringFromResource("/security_group_create_response.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + SecurityGroup.CreateOptions createSecurityGroup = SecurityGroup.createOptions().name("new-webservers") + .description("security group for webservers") + .build(); + + SecurityGroup securityGroup = api.create(createSecurityGroup); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/v2.0/security-groups", "/security_group_create_request.json"); + + /* + * Check response + */ + assertNotNull(securityGroup); + assertEquals(securityGroup.getId(), "2076db17-a522-4506-91de-c6dd8e837028"); + assertEquals(securityGroup.getTenantId(), "e4f50856753b4dc6afee5fa6b9b6c550"); + assertEquals(securityGroup.getName(), "new-webservers"); + assertEquals(securityGroup.getDescription(), "security group for webservers"); + + Rule sgr0 = securityGroup.getRules().get(0); + Rule sgr1 = securityGroup.getRules().get(1); + + assertEquals(sgr0.getId(), "38ce2d8e-e8f1-48bd-83c2-d33cb9f50c3d"); + assertEquals(sgr1.getId(), "565b9502-12de-4ffd-91e9-68885cff6ae1"); + } finally { + server.shutdown(); + } + } + + @Test(expectedExceptions = ResourceNotFoundException.class) + public void testCreateSecurityGroupFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + SecurityGroup.CreateOptions createSecurityGroup = SecurityGroup.createOptions().name("new-webservers") + .description("security group for webservers") + .build(); + + SecurityGroup securityGroup = api.create(createSecurityGroup); + } finally { + server.shutdown(); + } + } + + public void testCreateSecurityGroupRule() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(201).setBody(stringFromResource("/security_group_rule_create_response.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + Rule.CreateOptions createSecurityGroupRule = Rule.createOptions( + RuleDirection.INGRESS, "a7734e61-b545-452d-a3cd-0189cbd9747a") + .portRangeMin(80) + .portRangeMax(80) + .ethertype(RuleEthertype.IPV4) + .protocol(RuleProtocol.TCP) + .remoteGroupId("85cc3048-abc3-43cc-89b3-377341426ac5") + .build(); + + Rule rule = api.create(createSecurityGroupRule); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/v2.0/security-group-rules", "/security_group_rule_create_request.json"); + + /* + * Check response + */ + assertNotNull(rule); + assertEquals(rule.getId(), "2bc0accf-312e-429a-956e-e4407625eb62"); + assertEquals(rule.getTenantId(), "e4f50856753b4dc6afee5fa6b9b6c550"); + assertEquals(rule.getDirection(), RuleDirection.INGRESS); + assertEquals(rule.getPortRangeMax().intValue(), 80); + assertEquals(rule.getPortRangeMin().intValue(), 80); + assertEquals(rule.getEthertype(), RuleEthertype.IPV4); + assertEquals(rule.getProtocol(), RuleProtocol.TCP); + assertEquals(rule.getRemoteGroupId(), "85cc3048-abc3-43cc-89b3-377341426ac5"); + assertEquals(rule.getSecurityGroupId(), "a7734e61-b545-452d-a3cd-0189cbd9747a"); + + } finally { + server.shutdown(); + } + } + + @Test(expectedExceptions = ResourceNotFoundException.class) + public void testCreateSecurityGroupRuleFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + Rule.CreateOptions createSecurityGroupRule = Rule.createOptions( + RuleDirection.INGRESS, "a7734e61-b545-452d-a3cd-0189cbd9747a") + .portRangeMin(80) + .portRangeMax(80) + .ethertype(RuleEthertype.IPV4) + .protocol(RuleProtocol.TCP) + .remoteGroupId("85cc3048-abc3-43cc-89b3-377341426ac5") + .build(); + + Rule rule = api.create(createSecurityGroupRule); + } finally { + server.shutdown(); + } + } + + public void testListSpecificPageSecurityGroup() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/security_group_list_response_paged1.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + SecurityGroups securityGroups = api.listSecurityGroups(PaginationOptions.Builder.limit(2).marker("abcdefg")); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-groups?limit=2&marker=abcdefg"); + + /* + * Check response + */ + assertNotNull(securityGroups); + assertEquals(securityGroups.size(), 2); + assertEquals(securityGroups.first().get().getId(), "85cc3048-abc3-43cc-89b3-377341426ac5"); + assertEquals(securityGroups.get(1).getId(), "85cc3048-abc3-43cc-89b3-377341426ac52"); + } finally { + server.shutdown(); + } + } + + public void testListSpecificPageSecurityGroupFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + SecurityGroups securityGroups = api.listSecurityGroups(PaginationOptions.Builder.limit(2).marker("abcdefg")); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-groups?limit=2&marker=abcdefg"); + + /* + * Check response + */ + assertNotNull(securityGroups); + assertTrue(securityGroups.isEmpty()); + } finally { + server.shutdown(); + } + } + + public void testListSpecificPageSecurityGroupRule() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/security_group_rule_list_response_paged1.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + Rules rules = api.listRules(PaginationOptions.Builder.limit(2).marker("abcdefg")); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-group-rules?limit=2&marker=abcdefg"); + + /* + * Check response + */ + assertNotNull(rules); + assertEquals(rules.size(), 4); + assertEquals(rules.first().get().getId(), "3c0e45ff-adaf-4124-b083-bf390e5482ff"); + assertEquals(rules.get(3).getId(), "f7d45c89-008e-4bab-88ad-d6811724c51c"); + } finally { + server.shutdown(); + } + } + + public void testListSpecificPageSecurityGroupRuleFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + Rules rules = api.listRules(PaginationOptions.Builder.limit(2).marker("abcdefg")); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-group-rules?limit=2&marker=abcdefg"); + + /* + * Check response + */ + assertNotNull(rules); + assertTrue(rules.isEmpty()); + } finally { + server.shutdown(); + } + } + + public void testListPagedSecurityGroups() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/security_group_list_response_paged1.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/security_group_list_response_paged2.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + // Note: Lazy! Have to actually look at the collection. + List securityGroups = api.listSecurityGroups().concat().toList(); + + /* + * Check request + */ + assertEquals(server.getRequestCount(), 3); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-groups"); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-groups?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718"); + + /* + * Check response + */ + assertNotNull(securityGroups); + assertEquals(securityGroups.size(), 4); + assertEquals(securityGroups.get(0).getId(), "85cc3048-abc3-43cc-89b3-377341426ac5"); + assertEquals(securityGroups.get(3).getId(), "85cc3048-abc3-43cc-89b3-377341426ac524"); + + } finally { + server.shutdown(); + } + } + + public void testListPagedSecurityGroupsFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + // Note: Lazy! Have to actually look at the collection. + List securityGroups = api.listSecurityGroups().concat().toList(); + + /* + * Check request + */ + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-groups"); + + /* + * Check response + */ + assertNotNull(securityGroups); + assertTrue(securityGroups.isEmpty()); + + } finally { + server.shutdown(); + } + } + + public void testListPagedSecurityGroupRules() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/security_group_rule_list_response_paged1.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(200).setBody(stringFromResource("/security_group_rule_list_response_paged2.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + // Note: Lazy! Have to actually look at the collection. + List rules = api.listRules().concat().toList(); + + /* + * Check request + */ + assertEquals(server.getRequestCount(), 3); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-group-rules"); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-group-rules?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718"); + + /* + * Check response + */ + assertNotNull(rules); + assertEquals(rules.size(), 8); + assertEquals(rules.get(0).getId(), "3c0e45ff-adaf-4124-b083-bf390e5482ff"); + assertEquals(rules.get(7).getId(), "f7d45c89-008e-4bab-88ad-d6811724c51c2"); + + } finally { + server.shutdown(); + } + } + + public void testListPagedSecurityGroupRulesFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + // Note: Lazy! Have to actually look at the collection. + List rules = api.listRules().concat().toList(); + + /* + * Check request + */ + assertEquals(server.getRequestCount(), 2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-group-rules"); + + /* + * Check response + */ + assertNotNull(rules); + assertTrue(rules.isEmpty()); + + } finally { + server.shutdown(); + } + } + + public void testGetSecurityGroup() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(201).setBody(stringFromResource("/security_group_get_response.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + SecurityGroup securityGroup = api.getSecurityGroup("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-groups/12345"); + + /* + * Check response + */ + assertNotNull(securityGroup); + assertEquals(securityGroup.getName(), "default"); + assertEquals(securityGroup.getDescription(), "default"); + assertEquals(securityGroup.getId(), "85cc3048-abc3-43cc-89b3-377341426ac5"); + assertEquals(securityGroup.getTenantId(), "e4f50856753b4dc6afee5fa6b9b6c550"); + Rule sgr = securityGroup.getRules().get(0); + assertEquals(sgr.getId(), "3c0e45ff-adaf-4124-b083-bf390e5482ff"); + } finally { + server.shutdown(); + } + } + + public void testGetSecurityGroupFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + SecurityGroup securityGroup = api.getSecurityGroup("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-groups/12345"); + + /* + * Check response + */ + assertNull(securityGroup); + + } finally { + server.shutdown(); + } + } + + public void testGetSecurityGroupRule() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(201).setBody(stringFromResource("/security_group_rule_get_response.json")))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + Rule rule = api.get("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-group-rules/12345"); + + /* + * Check response + */ + assertNotNull(rule); + assertEquals(rule.getDirection(), RuleDirection.EGRESS); + assertEquals(rule.getEthertype(), RuleEthertype.IPV6); + assertEquals(rule.getId(), "3c0e45ff-adaf-4124-b083-bf390e5482ff"); + assertEquals(rule.getTenantId(), "e4f50856753b4dc6afee5fa6b9b6c550"); + assertEquals(rule.getSecurityGroupId(), "85cc3048-abc3-43cc-89b3-377341426ac5"); + + } finally { + server.shutdown(); + } + } + + public void testGetSecurityGroupRuleFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + Rule rule = api.get("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "GET", "/v2.0/security-group-rules/12345"); + + /* + * Check response + */ + assertNull(rule); + + } finally { + server.shutdown(); + } + } + + public void testDeleteSecurityGroup() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(201))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + boolean result = api.deleteSecurityGroup("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "DELETE", "/v2.0/security-groups/12345"); + + /* + * Check response + */ + assertTrue(result); + } finally { + server.shutdown(); + } + } + + public void testDeleteSecurityGroupFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + boolean result = api.deleteSecurityGroup("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "DELETE", "/v2.0/security-groups/12345"); + + /* + * Check response + */ + assertFalse(result); + } finally { + server.shutdown(); + } + } + + public void testDeleteSecurityGroupRule() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(201))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + boolean result = api.deleteRule("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "DELETE", "/v2.0/security-group-rules/12345"); + + /* + * Check response + */ + assertTrue(result); + } finally { + server.shutdown(); + } + } + + public void testDeleteSecurityGroupRuleFail() throws IOException, InterruptedException, URISyntaxException { + MockWebServer server = mockOpenStackServer(); + server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json")))); + server.enqueue(addCommonHeaders( + new MockResponse().setResponseCode(404))); + + try { + NeutronApi neutronApi = api(server.getUrl("/").toString(), "openstack-neutron", overrides); + SecurityGroupApi api = neutronApi.getSecurityGroupApi("RegionOne").get(); + + boolean result = api.deleteRule("12345"); + + /* + * Check request + */ + assertAuthentication(server); + assertRequest(server.takeRequest(), "DELETE", "/v2.0/security-group-rules/12345"); + + /* + * Check response + */ + assertFalse(result); + } finally { + server.shutdown(); + } + } +} diff --git a/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java b/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java index d1d3c3b146..738ede51db 100644 --- a/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java +++ b/apis/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java @@ -65,7 +65,7 @@ public class PortApiMockTest extends BaseNeutronApiMockTest { .name("port1") .adminStateUp(true) .deviceId("d6b4d3a5-c700-476f-b609-1493dd9dadc0") - .allowedAddressPairs(ImmutableSet.of(AddressPair.createOptions("12", "111.222.333.444").build())) + .allowedAddressPairs(ImmutableSet.of(AddressPair.builder("12", "111.222.333.444").build())) .build(); Port port = api.create(createPort); @@ -112,7 +112,7 @@ public class PortApiMockTest extends BaseNeutronApiMockTest { .name("port1") .adminStateUp(true) .deviceId("d6b4d3a5-c700-476f-b609-1493dd9dadc0") - .allowedAddressPairs(ImmutableSet.of(AddressPair.createOptions("12", "111.222.333.444").build())) + .allowedAddressPairs(ImmutableSet.of(AddressPair.builder("12", "111.222.333.444").build())) .build(); Port port = api.create(createPort); diff --git a/apis/openstack-neutron/src/test/resources/security_group_create_request.json b/apis/openstack-neutron/src/test/resources/security_group_create_request.json new file mode 100644 index 0000000000..8a93ef9345 --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_create_request.json @@ -0,0 +1,6 @@ +{ + "security_group": { + "name": "new-webservers", + "description": "security group for webservers" + } +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_create_response.json b/apis/openstack-neutron/src/test/resources/security_group_create_response.json new file mode 100644 index 0000000000..1ded3275cb --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_create_response.json @@ -0,0 +1,34 @@ +{ + "security_group": { + "description": "security group for webservers", + "id": "2076db17-a522-4506-91de-c6dd8e837028", + "name": "new-webservers", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv4", + "id": "38ce2d8e-e8f1-48bd-83c2-d33cb9f50c3d", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "2076db17-a522-4506-91de-c6dd8e837028", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv6", + "id": "565b9502-12de-4ffd-91e9-68885cff6ae1", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "2076db17-a522-4506-91de-c6dd8e837028", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_get_response.json b/apis/openstack-neutron/src/test/resources/security_group_get_response.json new file mode 100644 index 0000000000..126b5d20c9 --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_get_response.json @@ -0,0 +1,58 @@ +{ + "security_group": { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "name": "default", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e448", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_list_response.json b/apis/openstack-neutron/src/test/resources/security_group_list_response.json new file mode 100644 index 0000000000..c0cf7472ed --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_list_response.json @@ -0,0 +1,116 @@ +{ + "security_groups": [ + { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "name": "default", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e448", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac52", + "name": "default", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e4482", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d9281382", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ] +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_list_response_paged1.json b/apis/openstack-neutron/src/test/resources/security_group_list_response_paged1.json new file mode 100644 index 0000000000..dcf91c87c9 --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_list_response_paged1.json @@ -0,0 +1,126 @@ +{ + "security_groups": [ + { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "name": "default", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e448", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac52", + "name": "default", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e4482", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d9281382", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "security_groups_links": [ + { + "href": "/v2.0/security-groups.json?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718", + "rel": "next" + }, + { + "href": "/v2.0/security-groups.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True", + "rel": "previous" + } + ] +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_list_response_paged2.json b/apis/openstack-neutron/src/test/resources/security_group_list_response_paged2.json new file mode 100644 index 0000000000..ded8067573 --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_list_response_paged2.json @@ -0,0 +1,122 @@ +{ + "security_groups": [ + { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac53", + "name": "default", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e448", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac524", + "name": "default", + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e4482", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d9281382", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "security_groups_links": [ + { + "href": "/v2.0/security-groups.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True", + "rel": "previous" + } + ] +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_rule_create_request.json b/apis/openstack-neutron/src/test/resources/security_group_rule_create_request.json new file mode 100644 index 0000000000..14bea85cca --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_rule_create_request.json @@ -0,0 +1,11 @@ +{ + "security_group_rule": { + "direction": "ingress", + "port_range_min": 80, + "ethertype": "IPv4", + "port_range_max": 80, + "protocol": "tcp", + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a" + } +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_rule_create_response.json b/apis/openstack-neutron/src/test/resources/security_group_rule_create_response.json new file mode 100644 index 0000000000..0037e947f3 --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_rule_create_response.json @@ -0,0 +1,15 @@ +{ + "security_group_rule": { + "direction": "ingress", + "ethertype": "IPv4", + "id": "2bc0accf-312e-429a-956e-e4407625eb62", + "port_range_max": 80, + "port_range_min": 80, + "protocol": "tcp", + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } +} + diff --git a/apis/openstack-neutron/src/test/resources/security_group_rule_get_response.json b/apis/openstack-neutron/src/test/resources/security_group_rule_get_response.json new file mode 100644 index 0000000000..7225101fb4 --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_rule_get_response.json @@ -0,0 +1,14 @@ +{ + "security_group_rule": { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_rule_list_response.json b/apis/openstack-neutron/src/test/resources/security_group_rule_list_response.json new file mode 100644 index 0000000000..fbdeddf054 --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_rule_list_response.json @@ -0,0 +1,52 @@ +{ + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e448", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ] +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged1.json b/apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged1.json new file mode 100644 index 0000000000..5ecbfd311d --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged1.json @@ -0,0 +1,62 @@ +{ + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e448", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "security_group_rules_links": [ + { + "href": "/v2.0/security-group-rules.json?marker=71c1e68c-171a-4aa2-aca5-50ea153a3718", + "rel": "next" + }, + { + "href": "/v2.0/security-group-rules.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True", + "rel": "previous" + } + ] +} diff --git a/apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged2.json b/apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged2.json new file mode 100644 index 0000000000..1688ede4fb --- /dev/null +++ b/apis/openstack-neutron/src/test/resources/security_group_rule_list_response_paged2.json @@ -0,0 +1,58 @@ +{ + "security_group_rules": [ + { + "direction": "egress", + "ethertype": "IPv6", + "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "egress", + "ethertype": "IPv4", + "id": "93aa42e5-80db-4581-9391-3a608bd0e4482", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d9281382", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c2", + "port_range_max": null, + "port_range_min": null, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ], + "security_group_rules_links": [ + { + "href": "/v2.0/security-group-rules.json?marker=396f12f8-521e-4b91-8e21-2e003500433a&page_reverse=True", + "rel": "previous" + } + ] +}