You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by za...@apache.org on 2014/08/30 03:32:26 UTC
[1/2] Adds support for the Security Group extension to neutron
Repository: jclouds-labs-openstack
Updated Branches:
refs/heads/master de8348dd2 -> 67b9f4721
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiMockTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiMockTest.java
new file mode 100644
index 0000000..c14544d
--- /dev/null
+++ b/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<SecurityGroup> 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<SecurityGroup> 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<Rule> 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<Rule> 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();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java
index d1d3c3b..738ede5 100644
--- a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/features/PortApiMockTest.java
+++ b/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);
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_create_request.json b/openstack-neutron/src/test/resources/security_group_create_request.json
new file mode 100644
index 0000000..8a93ef9
--- /dev/null
+++ b/openstack-neutron/src/test/resources/security_group_create_request.json
@@ -0,0 +1,6 @@
+{
+ "security_group": {
+ "name": "new-webservers",
+ "description": "security group for webservers"
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_create_response.json b/openstack-neutron/src/test/resources/security_group_create_response.json
new file mode 100644
index 0000000..1ded327
--- /dev/null
+++ b/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"
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_get_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_get_response.json b/openstack-neutron/src/test/resources/security_group_get_response.json
new file mode 100644
index 0000000..126b5d2
--- /dev/null
+++ b/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"
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_list_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_list_response.json b/openstack-neutron/src/test/resources/security_group_list_response.json
new file mode 100644
index 0000000..c0cf747
--- /dev/null
+++ b/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"
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_list_response_paged1.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_list_response_paged1.json b/openstack-neutron/src/test/resources/security_group_list_response_paged1.json
new file mode 100644
index 0000000..dcf91c8
--- /dev/null
+++ b/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"
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_list_response_paged2.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_list_response_paged2.json b/openstack-neutron/src/test/resources/security_group_list_response_paged2.json
new file mode 100644
index 0000000..ded8067
--- /dev/null
+++ b/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"
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_rule_create_request.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_rule_create_request.json b/openstack-neutron/src/test/resources/security_group_rule_create_request.json
new file mode 100644
index 0000000..14bea85
--- /dev/null
+++ b/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"
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_rule_create_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_rule_create_response.json b/openstack-neutron/src/test/resources/security_group_rule_create_response.json
new file mode 100644
index 0000000..0037e94
--- /dev/null
+++ b/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"
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_rule_get_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_rule_get_response.json b/openstack-neutron/src/test/resources/security_group_rule_get_response.json
new file mode 100644
index 0000000..7225101
--- /dev/null
+++ b/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"
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_rule_list_response.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_rule_list_response.json b/openstack-neutron/src/test/resources/security_group_rule_list_response.json
new file mode 100644
index 0000000..fbdeddf
--- /dev/null
+++ b/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"
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_rule_list_response_paged1.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_rule_list_response_paged1.json b/openstack-neutron/src/test/resources/security_group_rule_list_response_paged1.json
new file mode 100644
index 0000000..5ecbfd3
--- /dev/null
+++ b/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"
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/resources/security_group_rule_list_response_paged2.json
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/resources/security_group_rule_list_response_paged2.json b/openstack-neutron/src/test/resources/security_group_rule_list_response_paged2.json
new file mode 100644
index 0000000..1688ede
--- /dev/null
+++ b/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"
+ }
+ ]
+}
[2/2] git commit: Adds support for the Security Group extension to
neutron
Posted by za...@apache.org.
Adds support for the Security Group extension to neutron
Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/commit/67b9f472
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/tree/67b9f472
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/diff/67b9f472
Branch: refs/heads/master
Commit: 67b9f47210156ca26139dfadad0eaa2a6b2fd8b8
Parents: de8348d
Author: Zack Shoylev <za...@rackspace.com>
Authored: Fri Aug 15 16:17:39 2014 -0500
Committer: Zack Shoylev <za...@rackspace.com>
Committed: Fri Aug 29 20:29:59 2014 -0500
----------------------------------------------------------------------
.../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 +
.../neutron/v2/extensions/SecurityGroupApi.java | 186 ++++++
.../v2/fallbacks/EmptyRulesFallback.java | 45 ++
.../fallbacks/EmptySecurityGroupsFallback.java | 45 ++
.../neutron/v2/functions/ParseRules.java | 38 ++
.../v2/functions/ParseSecurityGroups.java | 38 ++
.../v2/functions/RulesToPagedIterable.java | 66 ++
.../SecurityGroupsToPagedIterable.java | 66 ++
.../v2/extensions/SecurityGroupApiLiveTest.java | 88 +++
.../v2/extensions/SecurityGroupApiMockTest.java | 655 +++++++++++++++++++
.../neutron/v2/features/PortApiMockTest.java | 4 +-
.../security_group_create_request.json | 6 +
.../security_group_create_response.json | 34 +
.../resources/security_group_get_response.json | 58 ++
.../resources/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 ++
...ecurity_group_rule_list_response_paged1.json | 62 ++
...ecurity_group_rule_list_response_paged2.json | 58 ++
31 files changed, 2766 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java
index 233c41b..358e38f 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/NeutronApi.java
+++ b/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<? extends RouterApi> getRouterExtensionApi(@EndpointParam(parser = RegionToEndpoint.class) String region);
+ /**
+ * Provides access to SecurityGroup features.
+ *
+ * <h3>NOTE</h3>
+ * 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<SecurityGroupApi> getSecurityGroupApi(@EndpointParam(parser = RegionToEndpoint.class) String region);
}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java
index 4e317ce..a222908 100644
--- a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java
+++ b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/AddressPair.java
@@ -101,20 +101,11 @@ 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.
*/
public Builder toBuilder() {
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rule.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rule.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rule.java
new file mode 100644
index 0000000..e3b7aca
--- /dev/null
+++ b/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<ParameterizedBuilderType> {
+ // 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<CreateBuilder> {
+ /**
+ * 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.");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleDirection.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleDirection.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleDirection.java
new file mode 100644
index 0000000..759bb8c
--- /dev/null
+++ b/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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleEthertype.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleEthertype.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleEthertype.java
new file mode 100644
index 0000000..1508070
--- /dev/null
+++ b/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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleProtocol.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleProtocol.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/RuleProtocol.java
new file mode 100644
index 0000000..9ad105f
--- /dev/null
+++ b/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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rules.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rules.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/Rules.java
new file mode 100644
index 0000000..4794a18
--- /dev/null
+++ b/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<Rule> {
+ public static final Rules EMPTY = new Rules(ImmutableSet.<Rule> of(), ImmutableSet.<Link> of());
+
+ @ConstructorProperties({"security_group_rules", "security_group_rules_links"})
+ protected Rules(Iterable<Rule> securityGroups, Iterable<Link> securityGroupRulesLinks) {
+ super(securityGroups, securityGroupRulesLinks);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroup.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroup.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroup.java
new file mode 100644
index 0000000..604776e
--- /dev/null
+++ b/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<Rule> rules;
+
+ @ConstructorProperties({"id", "tenant_id", "name", "description", "security_group_rules"})
+ protected SecurityGroup(String id, String tenantId, String name, String description,
+ ImmutableList<Rule> 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<Rule> getRules() {
+ return rules!=null ? rules : ImmutableList.<Rule>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<ParameterizedBuilderType> {
+ // 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<CreateBuilder> {
+ /**
+ * 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);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroups.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroups.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/domain/SecurityGroups.java
new file mode 100644
index 0000000..044ce1c
--- /dev/null
+++ b/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<SecurityGroup> {
+ public static final SecurityGroups EMPTY = new SecurityGroups(ImmutableSet.<SecurityGroup> of(), ImmutableSet.<Link> of());
+
+ @ConstructorProperties({"security_groups", "security_groups_links"})
+ protected SecurityGroups(Iterable<SecurityGroup> securityGroups, Iterable<Link> securityGroupsLinks) {
+ super(securityGroups, securityGroupsLinks);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApi.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApi.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApi.java
new file mode 100644
index 0000000..4c0b4da
--- /dev/null
+++ b/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.
+ * <p/>
+ * 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<SecurityGroup> 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<Rule> 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);
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRulesFallback.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRulesFallback.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptyRulesFallback.java
new file mode 100644
index 0000000..a559f4f
--- /dev/null
+++ b/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<Rules> {
+
+ public ListenableFuture<Rules> 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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySecurityGroupsFallback.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySecurityGroupsFallback.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/fallbacks/EmptySecurityGroupsFallback.java
new file mode 100644
index 0000000..5343c3f
--- /dev/null
+++ b/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<SecurityGroups> {
+
+ public ListenableFuture<SecurityGroups> 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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRules.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRules.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseRules.java
new file mode 100644
index 0000000..954180b
--- /dev/null
+++ b/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<Rules> {
+
+ @Inject
+ public ParseRules(Json json) {
+ super(json, TypeLiteral.get(Rules.class));
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSecurityGroups.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSecurityGroups.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/ParseSecurityGroups.java
new file mode 100644
index 0000000..fbc3fd4
--- /dev/null
+++ b/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<SecurityGroups> {
+
+ @Inject
+ public ParseSecurityGroups(Json json) {
+ super(json, TypeLiteral.get(SecurityGroups.class));
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RulesToPagedIterable.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RulesToPagedIterable.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/RulesToPagedIterable.java
new file mode 100644
index 0000000..d664cd6
--- /dev/null
+++ b/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<Rule, RulesToPagedIterable> {
+
+ private final NeutronApi api;
+
+ @Inject
+ protected RulesToPagedIterable(NeutronApi api) {
+ this.api = checkNotNull(api, "api");
+ }
+
+ @Override
+ protected Function<Object, IterableWithMarker<Rule>> markerToNextForArg0(Optional<Object> arg0) {
+ String region = arg0.isPresent() ? arg0.get().toString() : null;
+ final SecurityGroupApi securityGroupApi = api.getSecurityGroupApi(region).get();
+ return new Function<Object, IterableWithMarker<Rule>>() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public IterableWithMarker<Rule> apply(Object input) {
+ PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+ return IterableWithMarker.class.cast(securityGroupApi.listRules(paginationOptions));
+ }
+
+ @Override
+ public String toString() {
+ return "listRules()";
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SecurityGroupsToPagedIterable.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SecurityGroupsToPagedIterable.java b/openstack-neutron/src/main/java/org/jclouds/openstack/neutron/v2/functions/SecurityGroupsToPagedIterable.java
new file mode 100644
index 0000000..15c7c14
--- /dev/null
+++ b/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<SecurityGroup, SecurityGroupsToPagedIterable> {
+
+ private final NeutronApi api;
+
+ @Inject
+ protected SecurityGroupsToPagedIterable(NeutronApi api) {
+ this.api = checkNotNull(api, "api");
+ }
+
+ @Override
+ protected Function<Object, IterableWithMarker<SecurityGroup>> markerToNextForArg0(Optional<Object> arg0) {
+ String region = arg0.isPresent() ? arg0.get().toString() : null;
+ final SecurityGroupApi securityGroupApi = api.getSecurityGroupApi(region).get();
+ return new Function<Object, IterableWithMarker<SecurityGroup>>() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public IterableWithMarker<SecurityGroup> apply(Object input) {
+ PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+ return IterableWithMarker.class.cast(securityGroupApi.listSecurityGroups(paginationOptions));
+ }
+
+ @Override
+ public String toString() {
+ return "listSecurityGroups()";
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/67b9f472/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiLiveTest.java b/openstack-neutron/src/test/java/org/jclouds/openstack/neutron/v2/extensions/SecurityGroupApiLiveTest.java
new file mode 100644
index 0000000..8771a3e
--- /dev/null
+++ b/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()));
+ }
+ }
+}