jclouds location customizer supports pre-release and post-release callback useful when the customizer is e.g. setting up then clearing external setup, e.g. DNS
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/fc4d4f79 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/fc4d4f79 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/fc4d4f79 Branch: refs/heads/master Commit: fc4d4f799c33e837a8973cd98a11d4b50eb072f0 Parents: 78776ca Author: Alex Heneveld <[email protected]> Authored: Wed May 6 09:21:43 2015 +0100 Committer: Alex Heneveld <[email protected]> Committed: Wed May 6 09:21:43 2015 +0100 ---------------------------------------------------------------------- .../jclouds/BasicJcloudsLocationCustomizer.java | 11 ++ .../location/jclouds/JcloudsLocation.java | 102 +++++++++++++------ .../jclouds/JcloudsLocationCustomizer.java | 11 ++ .../location/jclouds/JcloudsLocationTest.java | 39 ++++++- 4 files changed, 129 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fc4d4f79/locations/jclouds/src/main/java/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java index bebd97c..30f7700 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java @@ -55,4 +55,15 @@ public class BasicJcloudsLocationCustomizer implements JcloudsLocationCustomizer public void customize(JcloudsLocation location, ComputeService computeService, JcloudsSshMachineLocation machine) { // no-op } + + @Override + public void preRelease(JcloudsSshMachineLocation machine) { + // no-op + } + + @Override + public void postRelease(JcloudsSshMachineLocation machine) { + // no-op + } + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fc4d4f79/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java index d0c52d8..d27b06d 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java @@ -87,32 +87,6 @@ import org.jclouds.softlayer.compute.options.SoftLayerTemplateOptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.base.Objects; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.base.Splitter; -import com.google.common.base.Stopwatch; -import com.google.common.base.Supplier; -import com.google.common.base.Throwables; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.collect.Sets.SetView; -import com.google.common.io.Files; -import com.google.common.net.HostAndPort; -import com.google.common.primitives.Ints; -import com.google.common.reflect.TypeToken; - import brooklyn.config.ConfigKey; import brooklyn.config.ConfigKey.HasConfigKey; import brooklyn.config.ConfigUtils; @@ -173,6 +147,32 @@ import brooklyn.util.text.TemplateProcessor; import brooklyn.util.time.Duration; import brooklyn.util.time.Time; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Splitter; +import com.google.common.base.Stopwatch; +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.collect.Sets.SetView; +import com.google.common.io.Files; +import com.google.common.net.HostAndPort; +import com.google.common.primitives.Ints; +import com.google.common.reflect.TypeToken; + /** * For provisioning and managing VMs in a particular provider/region, using jclouds. * Configuration flags are defined in {@link JcloudsLocationConfig}. @@ -1630,11 +1630,16 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im String vmHostname = getPublicHostname(node, sshHostAndPort, setup); JcloudsSshMachineLocation machine = createJcloudsSshMachineLocation(computeService, node, vmHostname, sshHostAndPort, setup); - machine.setParent(this); - vmInstanceIds.put(machine, node.getId()); + registerJcloudsSshMachineLocation(node.getId(), machine); return machine; } + @VisibleForTesting + protected void registerJcloudsSshMachineLocation(String nodeId, JcloudsSshMachineLocation machine) { + machine.setParent(this); + vmInstanceIds.put(machine, nodeId); + } + /** @deprecated since 0.7.0 use variant which takes compute service; no longer called internally, * so marked final to force any overrides to switch to new syntax */ @Deprecated @@ -1764,24 +1769,57 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im LOG.info("Releasing machine {} in {}, instance id {}", new Object[] {machine, this, instanceId}); Exception tothrow = null; + + if (machine instanceof JcloudsSshMachineLocation) { + ConfigBag setup = config().getBag(); + for (JcloudsLocationCustomizer customizer : getCustomizers(setup)) { + try { + customizer.preRelease((JcloudsSshMachineLocation) machine); + } catch (Exception e) { + LOG.error("Problem invoking pre-release customizer "+customizer+" for machine "+machine+" in "+this+", instance id "+instanceId+ + "; ignoring and continuing, " + + (tothrow==null ? "will throw subsequently" : "swallowing due to previous error")+": "+e, e); + if (tothrow==null) tothrow = e; + } + } + } else { + LOG.warn("Releasing non-jclouds machine "+machine+" from "+this+"; skipping customizers"); + } + try { releasePortForwarding(machine); } catch (Exception e) { LOG.error("Problem releasing port-forwarding for machine "+machine+" in "+this+", instance id "+instanceId+ - "; discarding instance and continuing...", e); - tothrow = e; + "; ignoring and continuing, " + + (tothrow==null ? "will throw subsequently" : "swallowing due to previous error")+": "+e, e); + if (tothrow==null) tothrow = e; } try { releaseNode(instanceId); } catch (Exception e) { LOG.error("Problem releasing machine "+machine+" in "+this+", instance id "+instanceId+ - "; discarding instance and continuing...", e); - tothrow = e; + "; ignoring and continuing, " + + (tothrow==null ? "will throw subsequently" : "swallowing due to previous error")+": "+e, e); + if (tothrow==null) tothrow = e; } removeChild(machine); + if (machine instanceof JcloudsSshMachineLocation) { + ConfigBag setup = config().getBag(); + for (JcloudsLocationCustomizer customizer : getCustomizers(setup)) { + try { + customizer.postRelease((JcloudsSshMachineLocation) machine); + } catch (Exception e) { + LOG.error("Problem invoking pre-release customizer "+customizer+" for machine "+machine+" in "+this+", instance id "+instanceId+ + "; ignoring and continuing, " + + (tothrow==null ? "will throw subsequently" : "swallowing due to previous error")+": "+e, e); + if (tothrow==null) tothrow = e; + } + } + } + if (tothrow != null) { throw Exceptions.propagate(tothrow); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fc4d4f79/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationCustomizer.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationCustomizer.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationCustomizer.java index 6b1254e..94dc610 100644 --- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationCustomizer.java +++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationCustomizer.java @@ -65,4 +65,15 @@ public interface JcloudsLocationCustomizer { * machine is guaranteed to be SSHable when this method is called. */ void customize(JcloudsLocation location, ComputeService computeService, JcloudsSshMachineLocation machine); + + /** + * Override to handle machine-related cleanup before Jclouds is called to release (destroy) the machine. + */ + void preRelease(JcloudsSshMachineLocation machine); + + /** + * Override to handle machine-related cleanup after Jclouds is called to release (destroy) the machine. + */ + void postRelease(JcloudsSshMachineLocation machine); + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fc4d4f79/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java ---------------------------------------------------------------------- diff --git a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java index b41f24e..d08338d 100644 --- a/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java +++ b/locations/jclouds/src/test/java/brooklyn/location/jclouds/JcloudsLocationTest.java @@ -29,6 +29,7 @@ import javax.annotation.Nullable; import org.jclouds.compute.ComputeService; import org.jclouds.compute.domain.Template; +import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; @@ -55,6 +56,7 @@ import brooklyn.util.exceptions.Exceptions; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.reflect.TypeToken; @@ -501,11 +503,24 @@ public class JcloudsLocationTest implements JcloudsLocationConfig { @Override public JcloudsSshMachineLocation obtain(Map<?, ?> flags) throws NoMachinesAvailableException { - return getManagementContext().getLocationManager().createLocation(LocationSpec.create(JcloudsSshMachineLocation.class) + JcloudsSshMachineLocation result = getManagementContext().getLocationManager().createLocation(LocationSpec.create(JcloudsSshMachineLocation.class) .configure("address", "127.0.0.1") .configure("port", 22) .configure("user", "bob") .configure("jcloudsParent", this)); + registerJcloudsSshMachineLocation("bogus", result); + + // explicitly invoke this customizer, to comply with tests + for (JcloudsLocationCustomizer customizer : getCustomizers(config().getBag())) { + customizer.customize(this, null, result); + } + + return result; + } + + @Override + protected void releaseNode(String instanceId) { + // no-op } } @@ -553,5 +568,25 @@ public class JcloudsLocationTest implements JcloudsLocationConfig { Assert.assertEquals(geo.longitude, -77.47314d, 0.00001); } - // TODO more tests, where flags come in from resolver, named locations, etc + @Test + public void testInvokesCustomizerCallbacks() throws Exception { + JcloudsLocationCustomizer customizer = Mockito.mock(JcloudsLocationCustomizer.class); +// Mockito.when(customizer.customize(Mockito.any(JcloudsLocation.class), Mockito.any(ComputeService.class), Mockito.any(JcloudsSshMachineLocation.class))); + ConfigBag allConfig = ConfigBag.newInstance() + .configure(CLOUD_PROVIDER, "aws-ec2") + .configure(ACCESS_IDENTITY, "bogus") + .configure(ACCESS_CREDENTIAL, "bogus") + .configure(JcloudsLocationConfig.JCLOUDS_LOCATION_CUSTOMIZERS, ImmutableList.of(customizer)) + .configure(JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 1); + FakeLocalhostWithParentJcloudsLocation ll = managementContext.getLocationManager().createLocation(LocationSpec.create(FakeLocalhostWithParentJcloudsLocation.class).configure(allConfig.getAllConfig())); + JcloudsSshMachineLocation l = ll.obtain(); + Mockito.verify(customizer, Mockito.times(1)).customize(ll, null, l); + Mockito.verify(customizer, Mockito.never()).preRelease(l); + Mockito.verify(customizer, Mockito.never()).postRelease(l); + + ll.release(l); + Mockito.verify(customizer, Mockito.times(1)).preRelease(l); + Mockito.verify(customizer, Mockito.times(1)).postRelease(l); + } + }
