Repository: brooklyn-server
Updated Branches:
  refs/heads/master a36b6412d -> ceeb02207


Add Shared security group customizer

Can be instantiated in yaml


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/026d397e
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/026d397e
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/026d397e

Branch: refs/heads/master
Commit: 026d397e7f9ee70df33c0517b104702902485bd7
Parents: 215c02c
Author: Duncan Grant <duncan.gr...@cloudsoftcorp.com>
Authored: Fri Jul 29 13:11:14 2016 +0100
Committer: Duncan Grant <duncan.gr...@cloudsoftcorp.com>
Committed: Mon Aug 15 13:17:36 2016 +0100

----------------------------------------------------------------------
 .../SharedLocationSecurityGroupCustomizer.java  | 185 +++++++++++++++++++
 ...aredLocationSecurityGroupCustomizerTest.java | 150 +++++++++++++++
 2 files changed, 335 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/026d397e/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizer.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizer.java
 
b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizer.java
new file mode 100644
index 0000000..e393bae
--- /dev/null
+++ 
b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizer.java
@@ -0,0 +1,185 @@
+/*
+ * 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.apache.brooklyn.location.jclouds.networking;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.location.jclouds.BasicJcloudsLocationCustomizer;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsMachineLocation;
+import org.apache.brooklyn.util.net.Cidr;
+import org.apache.brooklyn.util.net.Networking;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.net.domain.IpPermission;
+import org.jclouds.net.domain.IpProtocol;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Strings;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Range;
+import com.google.common.collect.RangeSet;
+
+/**
+ * Configures a shared security group on Jclouds locations
+ * <p>
+ * Is based on {@link JcloudsLocationSecurityGroupCustomizer} but can be 
instantiated
+ * in yaml e.g.
+ * <p>
+ * <pre>
+ * {@code
+ * services:
+ * - type: org.apache.brooklyn.entity.software.base.EmptySoftwareProcess
+ *   brooklyn.config:
+ *     provisioning.properties:
+ *       customizers:
+ *       - $brooklyn:object:
+ *         type: 
org.apache.brooklyn.location.jclouds.networking.SharedLocationSecurityGroupCustomizer
+ *         object.fields: {locationName: "test", tcpPortRanges: ["900-910", 
"915", "22"], cidr: "82.40.153.101/24"}
+ * }
+ * </pre>
+*/
+public class SharedLocationSecurityGroupCustomizer extends 
BasicJcloudsLocationCustomizer {
+
+    private String locationName = null;
+
+    private String cidr = null;
+
+    /**
+     * We track inbound ports from the template to open them once we've 
created the new
+     * security groups
+     */
+    private int[] inboundPorts;
+
+    private RangeSet<Integer> tcpPortRanges;
+    private RangeSet<Integer> udpPortRanges;
+
+    /**
+     * The location name is appended to the name of the shared SG - use if you 
need distinct shared SGs within the same location
+     *
+     * @param locationName appended to the name of the SG
+     */
+    public void setLocationName(String locationName) {
+        this.locationName = locationName;
+    }
+
+    /**
+     * Extra ports to be opened on the entities in the SG
+     *
+     * @param tcpPortRanges
+     */
+    public void setTcpPortRanges(List<String> tcpPortRanges) {
+        this.tcpPortRanges = Networking.portRulesToRanges(tcpPortRanges);
+    }
+
+    public void setUdpPortRanges(ImmutableList<String> udpPortRanges) {
+        this.udpPortRanges = Networking.portRulesToRanges(udpPortRanges);
+    }
+
+    /**
+     * Set to restict the range that the ports that are to be opened can be 
accessed from
+     *
+     * @param cidr
+     */
+    public void setCidr(String cidr) {
+        this.cidr = cidr;
+    }
+
+    @Override
+    public void customize(JcloudsLocation location, ComputeService 
computeService, Template template) {
+        super.customize(location, computeService, template);
+
+        inboundPorts = template.getOptions().getInboundPorts();
+
+        final JcloudsLocationSecurityGroupCustomizer instance = 
getInstance(getSharedGroupId(location));
+        if (cidr != null) instance.setSshCidrSupplier(Suppliers.ofInstance(new 
Cidr(cidr)));
+        instance.customize(location, computeService, template);
+    }
+
+    @Override
+    public void customize(JcloudsLocation location, ComputeService 
computeService, JcloudsMachineLocation machine) {
+        super.customize(location, computeService, machine);
+
+        final JcloudsLocationSecurityGroupCustomizer instance = 
getInstance(getSharedGroupId(location));
+
+        ImmutableList.Builder<IpPermission> builder = 
ImmutableList.<IpPermission>builder();
+        builder.addAll(getIpPermissions(instance, tcpPortRanges, 
IpProtocol.TCP));
+        builder.addAll(getIpPermissions(instance, udpPortRanges, 
IpProtocol.UDP));
+
+        if (inboundPorts != null) {
+            for (int inboundPort : inboundPorts) {
+                IpPermission ipPermission = IpPermission.builder()
+                        .fromPort(inboundPort)
+                        .toPort(inboundPort)
+                        .ipProtocol(IpProtocol.TCP)
+                        .cidrBlock(instance.getBrooklynCidrBlock())
+                        .build();
+                builder.add(ipPermission);
+            }
+        }
+        instance.addPermissionsToLocation(machine, builder.build());
+    }
+
+    private List<IpPermission> 
getIpPermissions(JcloudsLocationSecurityGroupCustomizer instance, 
RangeSet<Integer> portRanges, IpProtocol protocol) {
+        List<IpPermission> ipPermissions = ImmutableList.<IpPermission>of();
+        if (portRanges != null) {
+             ipPermissions =
+                    FluentIterable
+                            .from(portRanges.asRanges())
+                            .transform(portRangeToPermission(instance, 
protocol))
+                            .toList();
+        }
+        return ipPermissions;
+    }
+
+    private Function<Range<Integer>, IpPermission> portRangeToPermission(final 
JcloudsLocationSecurityGroupCustomizer instance, final IpProtocol protocol) {
+        return new Function<Range<Integer>, IpPermission>() {
+            @Nullable
+            @Override
+            public IpPermission apply(@Nullable Range<Integer> integerRange) {
+                IpPermission extraPermission = IpPermission.builder()
+                        .fromPort(integerRange.lowerEndpoint())
+                        .toPort(integerRange.upperEndpoint())
+                        .ipProtocol(protocol)
+                        .cidrBlock(instance.getBrooklynCidrBlock())
+                        .build();
+                return extraPermission;
+            }
+        };
+    }
+
+    private String getSharedGroupId(JcloudsLocation location) {
+        return (Strings.isNullOrEmpty(locationName))
+                ? location.getId()
+                : locationName + "-" + location.getId();
+    }
+
+    @VisibleForTesting
+    JcloudsLocationSecurityGroupCustomizer getInstance(String sharedGroupId) {
+        return 
JcloudsLocationSecurityGroupCustomizer.getInstance(sharedGroupId);
+    }
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/026d397e/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizerTest.java
----------------------------------------------------------------------
diff --git 
a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizerTest.java
 
b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizerTest.java
new file mode 100644
index 0000000..565bd7b
--- /dev/null
+++ 
b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/SharedLocationSecurityGroupCustomizerTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.apache.brooklyn.location.jclouds.networking;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.net.Cidr;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.extensions.SecurityGroupExtension;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Location;
+import org.jclouds.net.domain.IpPermission;
+import org.jclouds.net.domain.IpProtocol;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
+public class SharedLocationSecurityGroupCustomizerTest {
+
+    TestSharedLocationSecurityGroupCustomizer customizer;
+    JcloudsLocationSecurityGroupCustomizer sgCustomizer;
+    ComputeService computeService;
+    Location location;
+    SecurityGroupExtension securityApi;
+    private JcloudsLocation jcloudsLocation = new 
JcloudsLocation(MutableMap.of("deferConstruction", true));
+    private Template mockTemplate;
+    private TemplateOptions mockOptions;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() {
+        sgCustomizer = mock(JcloudsLocationSecurityGroupCustomizer.class);
+        customizer = new TestSharedLocationSecurityGroupCustomizer();
+        location = mock(Location.class);
+        securityApi = mock(SecurityGroupExtension.class);
+        computeService = mock(ComputeService.class, 
Answers.RETURNS_DEEP_STUBS.get());
+        mockTemplate = mock(Template.class);
+        mockOptions = mock(TemplateOptions.class);
+        
when(computeService.getSecurityGroupExtension()).thenReturn(Optional.of(securityApi));
+        when(mockTemplate.getOptions()).thenReturn(mockOptions);
+        when(mockOptions.getInboundPorts()).thenReturn(new int[]{});
+    }
+
+    @Test
+    public void testLocationNameAppended() {
+        customizer.setLocationName("Fred");
+        customizer.customize(jcloudsLocation, computeService, mockTemplate);
+        assertEquals(customizer.sharedGroupId, "Fred-" + 
jcloudsLocation.getId());
+    }
+
+    @Test
+    public void testCidrIsSetIfAvailable() {
+        // Set cidr with over specified ip range which will be fixed by Cidr 
object
+        customizer.setCidr("1.1.1.1/24");
+        customizer.customize(jcloudsLocation, computeService, mockTemplate);
+        ArgumentCaptor<Supplier<Cidr>> argumentCaptor = 
ArgumentCaptor.forClass((Class)Supplier.class);
+        verify(sgCustomizer).setSshCidrSupplier(argumentCaptor.capture());
+        Cidr cidr = argumentCaptor.getValue().get();
+        assertEquals(cidr.toString(), "1.1.1.0/24");
+    }
+
+    @Test
+    public void testCidrNotSetIfNotavailable() {
+        customizer.customize(jcloudsLocation, computeService, mockTemplate);
+        verify(sgCustomizer, never()).setSshCidrSupplier(any(Supplier.class));
+    }
+
+
+    @Test
+    public void testPermissionsSetFromPortRanges() {
+        customizer.setTcpPortRanges(ImmutableList.of("99-100"));
+        when(sgCustomizer.getBrooklynCidrBlock()).thenReturn("10.10.10.10/24");
+        customizer.customize(jcloudsLocation, computeService, 
mock(JcloudsMachineLocation.class));
+        assertPermissionsAdded(99, 100, IpProtocol.TCP);
+    }
+
+    @Test
+    public void testUdpPermissionsSetFromPortRanges() {
+        customizer.setUdpPortRanges(ImmutableList.of("55-78"));
+        when(sgCustomizer.getBrooklynCidrBlock()).thenReturn("10.10.10.10/24");
+        customizer.customize(jcloudsLocation, computeService, 
mock(JcloudsMachineLocation.class));
+        assertPermissionsAdded(55, 78, IpProtocol.UDP);
+    }
+
+    @Test
+    public void testInboundPortsAddedToPermissions() {
+        when(mockOptions.getInboundPorts()).thenReturn(new int[]{5});
+        when(sgCustomizer.getBrooklynCidrBlock()).thenReturn("10.10.10.10/24");
+        customizer.customize(jcloudsLocation, computeService, mockTemplate);
+        customizer.customize(jcloudsLocation, computeService, 
mock(JcloudsMachineLocation.class));
+        assertPermissionsAdded(5, 5, IpProtocol.TCP);
+    }
+
+    private void assertPermissionsAdded(int expectedFrom, int expectedTo, 
IpProtocol expectedProtocol) {
+        ArgumentCaptor<List> listArgumentCaptor = 
ArgumentCaptor.forClass(List.class);
+        
verify(sgCustomizer).addPermissionsToLocation(any(JcloudsMachineLocation.class),
 listArgumentCaptor.capture());
+        IpPermission ipPermission = (IpPermission) 
listArgumentCaptor.getValue().get(0);
+        assertEquals(ipPermission.getFromPort(), expectedFrom);
+        assertEquals(ipPermission.getToPort(), expectedTo);
+        assertEquals(ipPermission.getIpProtocol(), expectedProtocol);
+    }
+
+    /**
+     * Used to skip external checks in unit tests.
+     */
+    private static class TestCidrSupplier implements Supplier<Cidr> {
+        @Override
+        public Cidr get() {
+            return new Cidr("192.168.10.10/32");
+        }
+    }
+
+    public class TestSharedLocationSecurityGroupCustomizer extends 
SharedLocationSecurityGroupCustomizer {
+        public String sharedGroupId;
+
+        @Override
+        JcloudsLocationSecurityGroupCustomizer getInstance(String 
sharedGroupId) {
+            this.sharedGroupId = sharedGroupId;
+            return sgCustomizer;
+        }
+    }
+}
\ No newline at end of file

Reply via email to