diff --git a/global-web-fabric/src/main/java/brooklyn/demo/GlobalWebFabricExample.groovy b/global-web-fabric/src/main/java/brooklyn/demo/GlobalWebFabricExample.groovy deleted file mode 100644 index 1ae05a2..0000000 --- a/global-web-fabric/src/main/java/brooklyn/demo/GlobalWebFabricExample.groovy +++ /dev/null @@ -1,76 +0,0 @@ -package brooklyn.demo - -import groovy.transform.InheritConstructors - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.config.BrooklynProperties -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.Attributes -import brooklyn.entity.basic.Entities -import brooklyn.entity.dns.geoscaling.GeoscalingDnsService -import brooklyn.entity.group.DynamicFabric -import brooklyn.entity.proxy.AbstractController; -import brooklyn.entity.webapp.ElasticJavaWebAppService -import brooklyn.event.basic.DependentConfiguration -import brooklyn.extras.cloudfoundry.CloudFoundryJavaWebAppCluster -import brooklyn.launcher.BrooklynLauncher -import brooklyn.location.Location -import brooklyn.location.basic.LocationRegistry -import brooklyn.util.CommandLineUtil - -@InheritConstructors -class GlobalWebFabricExample extends AbstractApplication { - - public static final Logger log = LoggerFactory.getLogger(GlobalWebFabricExample.class); - - public static final String WAR_PATH = "classpath://hello-world-webapp.war"; - - static final List DEFAULT_LOCATIONS = [ - "aws-ec2:eu-west-1", - "aws-ec2:ap-southeast-1", - "aws-ec2:us-west-1", -// "cloudfoundry:https://api.aws.af.cm/", - ]; - - static BrooklynProperties config = BrooklynProperties.Factory.newDefault() - - - DynamicFabric webFabric = new DynamicFabric(this, name: "Web Fabric", factory: new ElasticJavaWebAppService.Factory()); - - GeoscalingDnsService geoDns = new GeoscalingDnsService(this, name: "GeoScaling DNS", - username: config.getFirst("brooklyn.geoscaling.username", failIfNone:true), - password: config.getFirst("brooklyn.geoscaling.password", failIfNone:true), - primaryDomainName: config.getFirst("brooklyn.geoscaling.primaryDomain", failIfNone:true), - smartSubdomainName: 'brooklyn'); - - { - //specify the WAR file to use - webFabric.setConfig(ElasticJavaWebAppService.ROOT_WAR, WAR_PATH); - //load-balancer instances must run on 80 to work with GeoDNS (default is 8000) - webFabric.setConfig(AbstractController.PROXY_HTTP_PORT, 80); - //CloudFoundry requires to be told what URL it should listen to, which is chosen by the GeoDNS service - webFabric.setConfig(CloudFoundryJavaWebAppCluster.HOSTNAME_TO_USE_FOR_URL, - DependentConfiguration.attributeWhenReady(geoDns, Attributes.HOSTNAME)); - - //tell GeoDNS what to monitor - geoDns.setTargetEntityProvider(webFabric); - } - - - public static void main(String[] argv) { - GlobalWebFabricExample app = new GlobalWebFabricExample(name: 'Brooklyn Global Web Fabric Example'); - - ArrayList args = new ArrayList(Arrays.asList(argv)); - BrooklynLauncher.newLauncher(). - webconsolePort( CommandLineUtil.getCommandLineOption(args, "--port", "8081+") ). - managing(app). - launch(); - - List locations = new LocationRegistry().getLocationsById(args ?: DEFAULT_LOCATIONS); - app.start(locations); - Entities.dumpInfo(app); - } - -} diff --git a/global-web-fabric/src/main/java/brooklyn/demo/GlobalWebFabricExample.java b/global-web-fabric/src/main/java/brooklyn/demo/GlobalWebFabricExample.java new file mode 100644 index 0000000..8a51b1d --- /dev/null +++ b/global-web-fabric/src/main/java/brooklyn/demo/GlobalWebFabricExample.java @@ -0,0 +1,95 @@ +package brooklyn.demo; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.config.StringConfigMap; +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Attributes; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.dns.geoscaling.GeoscalingDnsService; +import brooklyn.entity.group.DynamicFabric; +import brooklyn.entity.proxy.AbstractController; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.ElasticJavaWebAppService; +import brooklyn.event.basic.DependentConfiguration; +import brooklyn.extras.cloudfoundry.CloudFoundryJavaWebAppCluster; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.location.basic.LocationRegistry; +import brooklyn.location.basic.PortRanges; +import brooklyn.util.CommandLineUtil; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +public class GlobalWebFabricExample extends ApplicationBuilder { + + public static final Logger log = LoggerFactory.getLogger(GlobalWebFabricExample.class); + + public static final String WAR_PATH = "classpath://hello-world-webapp.war"; + + static final List DEFAULT_LOCATIONS = ImmutableList.of( + "aws-ec2:eu-west-1", + "aws-ec2:ap-southeast-1", + "aws-ec2:us-west-1" +// "cloudfoundry:https://api.aws.af.cm/", + ); + + protected void doBuild() { + StringConfigMap config = getManagementContext().getConfig(); + + GeoscalingDnsService geoDns = createChild(BasicEntitySpec.newInstance(GeoscalingDnsService.class) + .displayName("GeoScaling DNS") + .configure("username", checkNotNull(config.getFirst("brooklyn.geoscaling.username"), "username")) + .configure("password", checkNotNull(config.getFirst("brooklyn.geoscaling.password"), "password")) + .configure("primaryDomainName", checkNotNull(config.getFirst("brooklyn.geoscaling.primaryDomain"), "primaryDomain")) + .configure("smartSubdomainName", "brooklyn")); + + DynamicFabric webFabric = createChild(BasicEntitySpec.newInstance(DynamicFabric.class) + .displayName("Web Fabric") + .configure(DynamicFabric.FACTORY, new ElasticJavaWebAppService.Factory()) + + //specify the WAR file to use + .configure(ElasticJavaWebAppService.ROOT_WAR, WAR_PATH) + + //load-balancer instances must run on 80 to work with GeoDNS (default is 8000) + .configure(AbstractController.PROXY_HTTP_PORT, PortRanges.fromInteger(80)) + + //CloudFoundry requires to be told what URL it should listen to, which is chosen by the GeoDNS service + .configure(CloudFoundryJavaWebAppCluster.HOSTNAME_TO_USE_FOR_URL, + DependentConfiguration.attributeWhenReady(geoDns, Attributes.HOSTNAME))); + + //tell GeoDNS what to monitor + geoDns.setTargetEntityProvider(webFabric); + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String locations = CommandLineUtil.getCommandLineOption(args, "--locations", Joiner.on(",").join(DEFAULT_LOCATIONS)); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + // TODO instead use server.getManagementContext().getLocationRegistry().resolve(location) + List locs = new LocationRegistry().getLocationsById(Arrays.asList(locations)); + + StartableApplication app = new GlobalWebFabricExample() + .appDisplayName("Brooklyn Global Web Fabric Example") + .manage(server.getManagementContext()); + + app.start(locs); + + Entities.dumpInfo(app); + } +} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebClusterWithHadoopExample.groovy b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebClusterWithHadoopExample.groovy deleted file mode 100644 index 84271a4..0000000 --- a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebClusterWithHadoopExample.groovy +++ /dev/null @@ -1,161 +0,0 @@ -package brooklyn.extras.whirr - -import groovy.transform.InheritConstructors - -import java.io.File -import java.net.InetAddress -import java.util.List - -import org.apache.log4j.lf5.util.StreamUtils; -import org.apache.whirr.service.hadoop.HadoopCluster -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.config.BrooklynProperties -import brooklyn.entity.Entity -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.DynamicGroup -import brooklyn.entity.basic.Entities -import brooklyn.entity.trait.Startable -import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; -import brooklyn.entity.webapp.DynamicWebAppCluster -import brooklyn.entity.webapp.jboss.JBoss7Server -import brooklyn.event.SensorEvent -import brooklyn.event.SensorEventListener -import brooklyn.event.adapter.HttpResponseContext -import brooklyn.extras.whirr.hadoop.WhirrHadoopCluster -import brooklyn.launcher.BrooklynLauncher -import brooklyn.location.Location -import brooklyn.location.basic.LocationRegistry -import brooklyn.management.Task -import brooklyn.policy.autoscaling.AutoScalerPolicy -import brooklyn.policy.basic.AbstractPolicy -import brooklyn.util.CommandLineUtil -import brooklyn.util.ResourceUtils; - -import com.google.common.base.Charsets -import com.google.common.collect.Iterables -import com.google.common.io.Files - -/** - * Starts hadoop and a webapp using hadoop in the location supplied (just one location), - * configuring the webapp to connect to hadoop - */ -@InheritConstructors -public class WebClusterWithHadoopExample extends AbstractApplication { - - private static final Logger log = LoggerFactory.getLogger(WebClusterWithHadoopExample.class); - - static final List DEFAULT_LOCATIONS = [ - // note the 1d: we need our machines to be in the same availability zone - // so they can see each other on the internal IPs (where hadoop binds) - // (cross-site magic is shown in the hadoop fabric example) - // ((also note some availability zones don't work, that's amazon for you...)) - // most other clouds "just work" :) - "aws-ec2:us-east-1d", - ]; - - public static final String WAR_PATH = "classpath://hello-world-hadoop-webapp.war"; - - static BrooklynProperties config = BrooklynProperties.Factory.newDefault() - - WhirrHadoopCluster hadoopCluster = new WhirrHadoopCluster(this, size: 2, memory: 2048, name: "Whirr Hadoop Cluster"); - { - // specify hadoop version (1.0.2 has a nice, smaller hadoop client jar) - hadoopCluster.addRecipeLine("whirr.hadoop.version=1.0.2"); - // for this example we'll allow access from anywhere - hadoopCluster.addRecipeLine("whirr.client-cidrs=0.0.0.0/0"); - hadoopCluster.addRecipeLine("whirr.firewall-rules=8020,8021,50010"); - } - - ControlledDynamicWebAppCluster webCluster = new ControlledDynamicWebAppCluster(this, war: WAR_PATH); - { - webCluster.addPolicy(AutoScalerPolicy.builder() - .metric(DynamicWebAppCluster.AVERAGE_REQUESTS_PER_SECOND) - .sizeRange(1, 5) - .metricRange(10, 100) - .build()) - } - - DynamicGroup webVms = new DynamicGroup(this, name: "Web VMs", { it in JBoss7Server }); - - void start(Collection locations) { - Iterables.getOnlyElement(locations); - log.debug("starting "+this); - super.start(locations); - - // start the web cluster, and hadoop cluster, in the single location (above) - // then register a policy to configure the appservers to use hadoop - log.debug("started "+this+", now starting policy"); - PrepVmsForHadoop.newPolicyFromGroupToHadoop(webVms, hadoopCluster); - } - - public static class PrepVmsForHadoop extends AbstractPolicy { - private static final Logger log = LoggerFactory.getLogger(WebClusterWithHadoopExample.class); - - WhirrHadoopCluster hadoopCluster; - String hadoopSiteXmlContents; - Set configuredIds = []; - - public PrepVmsForHadoop(WhirrHadoopCluster hadoopCluster) { - this.hadoopCluster = hadoopCluster; - } - - public void start() { - //read the contents, and disable socks proxy since we're in the same cluster - hadoopSiteXmlContents = new File("${System.getProperty('user.home')}/.whirr/"+ - hadoopCluster.clusterSpec.clusterName+"/hadoop-site.xml").text - hadoopSiteXmlContents = hadoopSiteXmlContents.replaceAll("<\\?xml.*\\?>\\s*", ""); - hadoopSiteXmlContents = hadoopSiteXmlContents.replaceAll("hadoop.socks.server", "ignore.hadoop.socks.server"); - - subscriptionTracker.subscribeToMembers(entity, Startable.SERVICE_UP, - { SensorEvent evt -> - log.debug "hadoop set up policy recieved {}", evt - if (evt.value && !configuredIds.contains(evt.source.id)) - setupMachine(evt.source) - } as SensorEventListener); - } - - public void setupMachine(Entity e) { - try { - if (!e.getAttribute(Startable.SERVICE_UP)) return; - if (!configuredIds.add(e.id)) return; - if (log.isDebugEnabled()) log.debug "setting up machine for hadoop at {}", e - - URL updateConfig = new URL(e.getAttribute(JBoss7Server.ROOT_URL)+ - "configure.jsp?"+ - "key=brooklyn.example.hadoop.site.xml.contents"+"&"+ - "value="+URLEncoder.encode(hadoopSiteXmlContents)); - def result = new HttpResponseContext(updateConfig.openConnection()); - if (log.isDebugEnabled()) log.debug "http config update for {} got: {}", e, result.content - } catch (Exception err) { - log.warn "unable to configure {} for hadoop: {}", e, err - configuredIds.remove(e.id); - } - } - - public static PrepVmsForHadoop newPolicyFromGroupToHadoop(DynamicGroup target, WhirrHadoopCluster hadoopCluster) { - log.debug "creating policy for hadoop clusters target {} hadoop ", target, hadoopCluster - PrepVmsForHadoop prepVmsForHadoop = new PrepVmsForHadoop(hadoopCluster); - target.addPolicy(prepVmsForHadoop); - prepVmsForHadoop.start(); - log.debug "running policy over existing members {}", target.members - target.members.each { prepVmsForHadoop.setupMachine(it) } - return prepVmsForHadoop; - } - } - - public static void main(String[] argv) { - ArrayList args = new ArrayList(Arrays.asList(argv)); - int port = CommandLineUtil.getCommandLineOptionInt(args, "--port", 8081); - List locations = new LocationRegistry().getLocationsById(args ?: DEFAULT_LOCATIONS) - log.info("starting WebClusterWithHadoop, locations {}, mgmt on port {}", locations, port) - - WebClusterWithHadoopExample app = new WebClusterWithHadoopExample(name: 'Brooklyn Global Web Fabric with Hadoop Example'); - - BrooklynLauncher.manage(app, port) - app.start(locations) - Entities.dumpInfo(app) - } - -} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebClusterWithHadoopExample.java b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebClusterWithHadoopExample.java new file mode 100644 index 0000000..ec8696e --- /dev/null +++ b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebClusterWithHadoopExample.java @@ -0,0 +1,212 @@ +package brooklyn.extras.whirr; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.config.StringConfigMap; +import brooklyn.entity.Entity; +import brooklyn.entity.Group; +import brooklyn.entity.basic.AbstractApplication; +import brooklyn.entity.basic.DynamicGroup; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.trait.Startable; +import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import brooklyn.entity.webapp.DynamicWebAppCluster; +import brooklyn.entity.webapp.jboss.JBoss7Server; +import brooklyn.event.SensorEvent; +import brooklyn.event.SensorEventListener; +import brooklyn.event.feed.http.HttpPollValue; +import brooklyn.extras.whirr.hadoop.WhirrHadoopCluster; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.policy.autoscaling.AutoScalerPolicy; +import brooklyn.policy.basic.AbstractPolicy; +import brooklyn.util.CommandLineUtil; +import brooklyn.util.exceptions.Exceptions; + +import com.google.common.base.Charsets; +import com.google.common.base.Joiner; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.io.Files; + +/** + * Starts hadoop and a webapp using hadoop in the location supplied (just one location), + * configuring the webapp to connect to hadoop + */ +public class WebClusterWithHadoopExample extends AbstractApplication implements StartableApplication { + + private static final Logger log = LoggerFactory.getLogger(WebClusterWithHadoopExample.class); + + static final List DEFAULT_LOCATIONS = ImmutableList.of( + // note the 1d: we need our machines to be in the same availability zone + // so they can see each other on the internal IPs (where hadoop binds) + // (cross-site magic is shown in the hadoop fabric example) + // ((also note some availability zones don't work, that's amazon for you...)) + // most other clouds "just work" :) + "aws-ec2:us-east-1c"); + + public static final String WAR_PATH = "classpath://hello-world-hadoop-webapp.war"; + + private WhirrHadoopCluster hadoopCluster; + private ControlledDynamicWebAppCluster webCluster; + private DynamicGroup webVms; + + public WebClusterWithHadoopExample() { + } + + @Override + public void postConstruct() { + StringConfigMap config = getManagementSupport().getManagementContext(true).getConfig(); + + hadoopCluster = getEntityManager().createEntity(BasicEntitySpec.newInstance(WhirrHadoopCluster.class) + .parent(this) + .configure("size", 2) + .configure("memory", 2048) + .configure("name", "Whirr Hadoop Cluster")); + + // TODO Can't just set RECIPE config in spec, because that overwrites defaults in WhirrHadoopCluster! + // specify hadoop version (1.0.2 has a nice, smaller hadoop client jar) + hadoopCluster.addRecipeLine("whirr.hadoop.version=1.0.2"); + // for this example we'll allow access from anywhere + hadoopCluster.addRecipeLine("whirr.client-cidrs=0.0.0.0/0"); + hadoopCluster.addRecipeLine("whirr.firewall-rules=8020,8021,50010"); + + webCluster = getEntityManager().createEntity(BasicEntitySpec.newInstance(ControlledDynamicWebAppCluster.class) + .parent(this) + .configure("war", WAR_PATH) + .policy(AutoScalerPolicy.builder() + .metric(DynamicWebAppCluster.AVERAGE_REQUESTS_PER_SECOND) + .sizeRange(1, 5) + .metricRange(10, 100) + .build())); + + webVms = getEntityManager().createEntity(BasicEntitySpec.newInstance(DynamicGroup.class) + .parent(this) + .displayName("Web VMs") + .configure(DynamicGroup.ENTITY_FILTER, Predicates.instanceOf(JBoss7Server.class))); + } + + @Override + public void start(Collection locations) { + Iterables.getOnlyElement(locations); + log.debug("starting "+this); + super.start(locations); + + // start the web cluster, and hadoop cluster, in the single location (above) + // then register a policy to configure the appservers to use hadoop + log.debug("started "+this+", now starting policy"); + PrepVmsForHadoop.newPolicyFromGroupToHadoop(webVms, hadoopCluster); + } + + public static class PrepVmsForHadoop extends AbstractPolicy { + WhirrHadoopCluster hadoopCluster; + String hadoopSiteXmlContents; + Set configuredIds = Sets.newLinkedHashSet(); + + public PrepVmsForHadoop(WhirrHadoopCluster hadoopCluster) { + this.hadoopCluster = hadoopCluster; + } + + public void start() { + //read the contents, and disable socks proxy since we're in the same cluster + try { + File hadoopSiteXmlFile = new File(System.getProperty("user.home")+"/.whirr/"+ + hadoopCluster.getClusterSpec().getClusterName()+"/hadoop-site.xml"); + hadoopSiteXmlContents = Files.toString(hadoopSiteXmlFile, Charsets.UTF_8); + hadoopSiteXmlContents = hadoopSiteXmlContents.replaceAll("<\\?xml.*\\?>\\s*", ""); + hadoopSiteXmlContents = hadoopSiteXmlContents.replaceAll("hadoop.socks.server", "ignore.hadoop.socks.server"); + + subscribeToMembers((Group)entity, Startable.SERVICE_UP, new SensorEventListener() { + @Override public void onEvent(SensorEvent event) { + log.debug("hadoop set up policy recieved {}", event); + if (event.getValue() != null && !configuredIds.contains(event.getSource().getId())) + setupMachine(event.getSource()); + }}); + } catch (IOException e) { + throw Exceptions.propagate(e); + } + } + + public void setupMachine(Entity e) { + try { + if (!e.getAttribute(Startable.SERVICE_UP)) return; + if (!configuredIds.add(e.getId())) return; + if (log.isDebugEnabled()) log.debug("setting up machine for hadoop at {}", e); + + URI updateConfigUri = new URI(e.getAttribute(JBoss7Server.ROOT_URL)+ + "configure.jsp?"+ + "key=brooklyn.example.hadoop.site.xml.contents"+"&"+ + "value="+URLEncoder.encode(hadoopSiteXmlContents)); + + HttpPollValue result = executeGet(updateConfigUri); + if (log.isDebugEnabled()) log.debug("http config update for {} got: {}, {}", new Object[] {e, result.getResponseCode(), new String(result.getContent())}); + } catch (Exception err) { + log.warn("unable to configure "+e+" for hadoop", err); + configuredIds.remove(e.getId()); + } + } + + private HttpPollValue executeGet(URI uri) throws ClientProtocolException, IOException { + DefaultHttpClient httpClient = new DefaultHttpClient(); + HttpGet httpGet = new HttpGet(uri); + HttpResponse httpResponse = httpClient.execute(httpGet); + try { + return new HttpPollValue(httpResponse); + } finally { + EntityUtils.consume(httpResponse.getEntity()); + } + } + + public static PrepVmsForHadoop newPolicyFromGroupToHadoop(DynamicGroup target, WhirrHadoopCluster hadoopCluster) { + log.debug("creating policy for hadoop clusters target {} hadoop ", target, hadoopCluster); + PrepVmsForHadoop prepVmsForHadoop = new PrepVmsForHadoop(hadoopCluster); + target.addPolicy(prepVmsForHadoop); + prepVmsForHadoop.start(); + log.debug("running policy over existing members {}", target.getMembers()); + for (Entity member : target.getMembers()) { + prepVmsForHadoop.setupMachine(member); + } + return prepVmsForHadoop; + } + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", Joiner.on(",").join(DEFAULT_LOCATIONS)); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = server.getManagementContext().getEntityManager().createEntity(BasicEntitySpec.newInstance(StartableApplication.class) + .displayName("Brooklyn Global Web Fabric with Hadoop Example") + .impl(WebClusterWithHadoopExample.class)); + Entities.startManagement(app, server.getManagementContext()); + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } +} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebFabricWithHadoopExample.groovy b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebFabricWithHadoopExample.groovy deleted file mode 100644 index f235999..0000000 --- a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebFabricWithHadoopExample.groovy +++ /dev/null @@ -1,204 +0,0 @@ -package brooklyn.extras.whirr - -import groovy.transform.InheritConstructors - -import org.apache.whirr.service.hadoop.HadoopCluster -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.config.BrooklynProperties -import brooklyn.entity.Entity -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.Attributes -import brooklyn.entity.basic.DynamicGroup -import brooklyn.entity.basic.Entities -import brooklyn.entity.dns.geoscaling.GeoscalingDnsService -import brooklyn.entity.group.DynamicFabric -import brooklyn.entity.trait.Startable -import brooklyn.entity.webapp.ElasticJavaWebAppService -import brooklyn.entity.webapp.jboss.JBoss7Server -import brooklyn.event.SensorEvent -import brooklyn.event.SensorEventListener -import brooklyn.event.adapter.HttpResponseContext -import brooklyn.event.basic.DependentConfiguration -import brooklyn.extras.cloudfoundry.CloudFoundryJavaWebAppCluster -import brooklyn.extras.whirr.hadoop.WhirrHadoopCluster -import brooklyn.launcher.BrooklynLauncher -import brooklyn.location.Location -import brooklyn.location.basic.LocationRegistry -import brooklyn.location.basic.SshMachineLocation -import brooklyn.management.Task -import brooklyn.policy.basic.AbstractPolicy -import brooklyn.util.CommandLineUtil -import brooklyn.util.task.ParallelTask - -import com.google.common.base.Charsets -import com.google.common.collect.Iterables -import com.google.common.collect.Lists -import com.google.common.io.Files - -/** - * Starts hadoop in the first location supplied, and the hadoop-friendly webapp in all other locations. - * Webapp get configured via the configure.jsp page, plus supplying the proxy command, to connect to hadoop. - */ -@InheritConstructors -public class WebFabricWithHadoopExample extends AbstractApplication { - - private static final Logger log = LoggerFactory.getLogger(WebFabricWithHadoopExample.class); - - static final List DEFAULT_LOCATIONS = [ - // hadoop location - "aws-ec2:eu-west-1", - - //web locations - "aws-ec2:eu-west-1", - "aws-ec2:ap-southeast-1", - "aws-ec2:us-west-1", - - // cloudfoundry seems to have a timeout in upload time - // (in any case we don't have a clean way to initiate the proxy settings in there) -// "cloudfoundry:https://api.aws.af.cm/", - ]; - - public static final String WAR_PATH = "classpath://hello-world-hadoop-webapp.war"; - - static BrooklynProperties config = BrooklynProperties.Factory.newDefault() - - WhirrHadoopCluster hadoopCluster = new WhirrHadoopCluster(this, size: 2, memory: 2048, name: "Whirr Hadoop Cluster"); - { hadoopCluster.addRecipeLine("whirr.hadoop.version=1.0.2"); } - - DynamicFabric webFabric = new DynamicFabric(this, name: "Web Fabric", factory: new ElasticJavaWebAppService.Factory()); - - GeoscalingDnsService geoDns = new GeoscalingDnsService(this, name: "GeoScaling DNS", - username: config.getFirst("brooklyn.geoscaling.username", failIfNone:true), - password: config.getFirst("brooklyn.geoscaling.password", failIfNone:true), - primaryDomainName: config.getFirst("brooklyn.geoscaling.primaryDomain", failIfNone:true), - smartSubdomainName: 'brooklyn'); - - { - //specify the WAR file to use - webFabric.setConfig(ElasticJavaWebAppService.ROOT_WAR, WAR_PATH); - //load-balancer instances must run on 80 to work with GeoDNS (default is 8000) - webFabric.setConfig(AbstractController.PROXY_HTTP_PORT, 80); - //CloudFoundry requires to be told what URL it should listen to, which is chosen by the GeoDNS service - webFabric.setConfig(CloudFoundryJavaWebAppCluster.HOSTNAME_TO_USE_FOR_URL, - DependentConfiguration.attributeWhenReady(geoDns, Attributes.HOSTNAME)); - - //tell GeoDNS what to monitor - geoDns.setTargetEntityProvider(webFabric); - } - - DynamicGroup webVms = new DynamicGroup(this, name: "Web VMs", { it in JBoss7Server }); - - void start(Collection locations) { - Location hadoopLocation = Iterables.getFirst(locations, null); - if (hadoopLocation==null) throw new IllegalStateException("location required to start $this"); - // start hadoop in first, web in others (unless there is just one location supplied) - List webLocations = Lists.newArrayList(Iterables.skip(locations, 1)) ?: [hadoopLocation]; - - Task starts = executionContext.submit(new ParallelTask( - { webFabric.start(webLocations) }, - { hadoopCluster.start([hadoopLocation]); - // collect the hadoop-site.xml and feed it to all existing and new appservers, - // and start the proxies there - PrepVmsForHadoop.newPolicyFromGroupToHadoop(webVms, hadoopCluster); - } )); - starts.blockUntilEnded(); - } - - public static class PrepVmsForHadoop extends AbstractPolicy { - private static final Logger log = LoggerFactory.getLogger(WebFabricWithHadoopExample.class); - - WhirrHadoopCluster hadoopCluster; - Set configuredIds = [] - - public PrepVmsForHadoop(WhirrHadoopCluster hadoopCluster) { - this.hadoopCluster = hadoopCluster; - } - - public static PrepVmsForHadoop newPolicyFromGroupToHadoop(DynamicGroup target, WhirrHadoopCluster hadoopCluster) { - log.debug "creating policy for hadoop clusters target {} hadoop ", target, hadoopCluster - PrepVmsForHadoop prepVmsForHadoop = new PrepVmsForHadoop(hadoopCluster); - target.addPolicy(prepVmsForHadoop); - prepVmsForHadoop.start(); - log.debug "running policy over existing members {}", target.members - target.members.each { prepVmsForHadoop.setupMachine(it) } - return prepVmsForHadoop; - } - - public void start() { - subscriptionTracker.subscribeToMembers(entity, Startable.SERVICE_UP, - { SensorEvent evt -> - log.debug "hadoop set up policy recieved {}", evt - if (evt.value) setupMachine(evt.source) } as SensorEventListener); - } - public void setupMachine(Entity e) { - try { - if (log.isDebugEnabled()) log.debug "setting up machine for hadoop at {}", e - if (!e.getAttribute(Startable.SERVICE_UP)) return; - if (!configuredIds.add(e.id)) return; - SshMachineLocation ssh = Iterables.getOnlyElement(e.locations); - //would prefer to extract content from HadoopNameNodeClusterActionHandler (but that class would need refactoring) - ssh.copyTo(new File("${System.getProperty('user.home')}/.whirr/"+hadoopCluster.clusterSpec.clusterName+"/hadoop-site.xml"), "/tmp/hadoop-site.xml"); - - File identity = hadoopCluster.clusterSpec.getPrivateKeyFile(); - if (identity == null){ - identity = File.createTempFile("hadoop", "key"); - identity.deleteOnExit(); - Files.write(hadoopCluster.clusterSpec.getPrivateKey(), identity, Charsets.UTF_8); - } - if (log.isDebugEnabled()) log.debug "http config update for {}, identity file: {}", e, identity - ssh.copyTo(identity, "/tmp/hadoop-proxy-private-key"); - - //copied from HadoopProxy, would prefer to reference (but again refactoring there is needed) - String user = hadoopCluster.clusterSpec.getClusterUser(); - InetAddress namenode = HadoopCluster.getNamenodePublicAddress(hadoopCluster.cluster); - String server = namenode.getHostName(); - String proxyCommand = [ "ssh", - "-i", "/tmp/hadoop-proxy-private-key", - "-o", "ConnectTimeout=10", - "-o", "ServerAliveInterval=60", - "-o", "StrictHostKeyChecking=no", - "-o", "UserKnownHostsFile=/dev/null", - "-o", "StrictHostKeyChecking=no", - "-N", - "-D 6666", - String.format("%s@%s", user, server) ].join(" "); - if (log.isDebugEnabled()) log.debug "http config update for {}, proxy command: {}", e, proxyCommand - - ssh.copyTo(new StringReader(""" -while [ true ] ; do - date - echo starting proxy for hadoop to """+String.format("%s@%s", user, server)+""" - nohup """+proxyCommand+""" - echo proxy ended -done -"""), "/tmp/hadoop-proxy-forever.sh"); - ssh.run("chmod 600 /tmp/hadoop-proxy-private-key ; chmod +x /tmp/hadoop-proxy-forever.sh ; nohup /tmp/hadoop-proxy-forever.sh &"); - - URL updateConfig = new URL(e.getAttribute(JBoss7Server.ROOT_URL)+ - "configure.jsp?key=brooklyn.example.hadoop.site.xml.url&value=file:///tmp/hadoop-site.xml"); - - def result = new HttpResponseContext(updateConfig.openConnection()); - if (log.isDebugEnabled()) log.debug "http config update for {} got: {}", e, result.content - } catch (Exception err) { - log.warn "unable to configure {} for hadoop: {}", e, err - configuredIds.remove(e.id); - } - } - } - - public static void main(String[] argv) { - ArrayList args = new ArrayList(Arrays.asList(argv)); - int port = CommandLineUtil.getCommandLineOptionInt(args, "--port", 8081); - List locations = new LocationRegistry().getLocationsById(args ?: DEFAULT_LOCATIONS) - log.info("starting WebFabricWithHadoop, locations {}, mgmt on port {}", locations, port) - - WebFabricWithHadoopExample app = new WebFabricWithHadoopExample(name: 'Brooklyn Global Web Fabric with Hadoop Example'); - - BrooklynLauncher.manage(app, port) - app.start(locations) - Entities.dumpInfo(app) - } - -} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebFabricWithHadoopExample.java b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebFabricWithHadoopExample.java new file mode 100644 index 0000000..aa503a6 --- /dev/null +++ b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WebFabricWithHadoopExample.java @@ -0,0 +1,290 @@ +package brooklyn.extras.whirr; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.net.InetAddress; +import java.net.URI; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.apache.whirr.service.hadoop.HadoopCluster; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.config.StringConfigMap; +import brooklyn.entity.Entity; +import brooklyn.entity.Group; +import brooklyn.entity.basic.AbstractApplication; +import brooklyn.entity.basic.Attributes; +import brooklyn.entity.basic.DynamicGroup; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.dns.geoscaling.GeoscalingDnsService; +import brooklyn.entity.group.DynamicFabric; +import brooklyn.entity.proxy.AbstractController; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.trait.Startable; +import brooklyn.entity.webapp.ElasticJavaWebAppService; +import brooklyn.entity.webapp.jboss.JBoss7Server; +import brooklyn.event.SensorEvent; +import brooklyn.event.SensorEventListener; +import brooklyn.event.basic.DependentConfiguration; +import brooklyn.event.feed.http.HttpPollValue; +import brooklyn.extras.cloudfoundry.CloudFoundryJavaWebAppCluster; +import brooklyn.extras.whirr.hadoop.WhirrHadoopCluster; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.location.basic.LocationRegistry; +import brooklyn.location.basic.PortRanges; +import brooklyn.location.basic.SshMachineLocation; +import brooklyn.management.Task; +import brooklyn.policy.basic.AbstractPolicy; +import brooklyn.util.CommandLineUtil; +import brooklyn.util.task.ParallelTask; + +import com.google.common.base.Charsets; +import com.google.common.base.Joiner; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.io.Files; + +/** + * Starts hadoop in the first location supplied, and the hadoop-friendly webapp in all other locations. + * Webapp get configured via the configure.jsp page, plus supplying the proxy command, to connect to hadoop. + */ +public class WebFabricWithHadoopExample extends AbstractApplication implements StartableApplication { + + private static final Logger log = LoggerFactory.getLogger(WebFabricWithHadoopExample.class); + + static final List DEFAULT_LOCATIONS = ImmutableList.of( + // hadoop location + "aws-ec2:eu-west-1", + + //web locations + "aws-ec2:eu-west-1", + "aws-ec2:ap-southeast-1", + "aws-ec2:us-west-1" + + // cloudfoundry seems to have a timeout in upload time + // (in any case we don't have a clean way to initiate the proxy settings in there) +// "cloudfoundry:https://api.aws.af.cm/", + ); + + public static final String WAR_PATH = "classpath://hello-world-hadoop-webapp.war"; + + private WhirrHadoopCluster hadoopCluster; + private GeoscalingDnsService geoDns; + private DynamicFabric webFabric; + private DynamicGroup webVms; + + public WebFabricWithHadoopExample() { + } + + @Override + public void postConstruct() { + StringConfigMap config = getManagementSupport().getManagementContext(true).getConfig(); + + hadoopCluster = getEntityManager().createEntity(BasicEntitySpec.newInstance(WhirrHadoopCluster.class) + .parent(this) + .configure("size", 2) + .configure("memory", 2048) + .configure("name", "Whirr Hadoop Cluster")); + + // TODO Can't just set RECIPE config in spec, because that overwrites defaults in WhirrHadoopCluster! + // specify hadoop version (1.0.2 has a nice, smaller hadoop client jar) + hadoopCluster.addRecipeLine("whirr.hadoop.version=1.0.2"); + + GeoscalingDnsService geoDns = getEntityManager().createEntity(BasicEntitySpec.newInstance(GeoscalingDnsService.class) + .parent(this) + .displayName("GeoScaling DNS") + .configure("username", checkNotNull(config.getFirst("brooklyn.geoscaling.username"), "username")) + .configure("password", checkNotNull(config.getFirst("brooklyn.geoscaling.password"), "password")) + .configure("primaryDomainName", checkNotNull(config.getFirst("brooklyn.geoscaling.primaryDomain"), "primaryDomain")) + .configure("smartSubdomainName", "brooklyn")); + + webFabric = getEntityManager().createEntity(BasicEntitySpec.newInstance(DynamicFabric.class) + .parent(this) + .displayName("Web Fabric") + .configure("factory", new ElasticJavaWebAppService.Factory()) + //specify the WAR file to use + .configure(ElasticJavaWebAppService.ROOT_WAR, WAR_PATH) + //load-balancer instances must run on 80 to work with GeoDNS (default is 8000) + .configure(AbstractController.PROXY_HTTP_PORT, PortRanges.fromInteger(80)) + //CloudFoundry requires to be told what URL it should listen to, which is chosen by the GeoDNS service + .configure(CloudFoundryJavaWebAppCluster.HOSTNAME_TO_USE_FOR_URL, + DependentConfiguration.attributeWhenReady(geoDns, Attributes.HOSTNAME)) + ); +// .policy(AutoScalerPolicy.builder() +// .metric(DynamicWebAppCluster.AVERAGE_REQUESTS_PER_SECOND) +// .sizeRange(1, 5) +// .metricRange(10, 100) +// .build())); + + webVms = getEntityManager().createEntity(BasicEntitySpec.newInstance(DynamicGroup.class) + .parent(this) + .displayName("Web VMs") + .configure(DynamicGroup.ENTITY_FILTER, Predicates.instanceOf(JBoss7Server.class))); + + //tell GeoDNS what to monitor + geoDns.setTargetEntityProvider(webFabric); + } + + @Override + public void start(Collection locations) { + if (locations.isEmpty()) throw new IllegalStateException("location required to start "+this); + final Location hadoopLocation = Iterables.getFirst(locations, null); + // start hadoop in first, web in others (unless there is just one location supplied) + final List webLocations = (locations.size() > 1) ? ImmutableList.copyOf(Iterables.skip(locations, 1)) : ImmutableList.of(hadoopLocation); + + Task> starts = getExecutionContext().submit(new ParallelTask( + new Runnable() { + public void run() { + webFabric.start(webLocations); + } + }, + new Runnable() { + public void run() { + hadoopCluster.start(ImmutableList.of(hadoopLocation)); + // collect the hadoop-site.xml and feed it to all existing and new appservers, + // and start the proxies there + PrepVmsForHadoop.newPolicyFromGroupToHadoop(webVms, hadoopCluster); + } + })); + starts.blockUntilEnded(); + } + + public static class PrepVmsForHadoop extends AbstractPolicy { + WhirrHadoopCluster hadoopCluster; + Set configuredIds = Sets.newLinkedHashSet(); + + public PrepVmsForHadoop(WhirrHadoopCluster hadoopCluster) { + this.hadoopCluster = hadoopCluster; + } + + public static PrepVmsForHadoop newPolicyFromGroupToHadoop(DynamicGroup target, WhirrHadoopCluster hadoopCluster) { + log.debug("creating policy for hadoop clusters target {} hadoop ", target, hadoopCluster); + PrepVmsForHadoop prepVmsForHadoop = new PrepVmsForHadoop(hadoopCluster); + target.addPolicy(prepVmsForHadoop); + prepVmsForHadoop.start(); + log.debug("running policy over existing members {}", target.getMembers()); + for (Entity member : target.getMembers()) { + prepVmsForHadoop.setupMachine(member); + } + return prepVmsForHadoop; + } + + public void start() { + subscribeToMembers((Group)entity, Startable.SERVICE_UP, new SensorEventListener() { + @Override public void onEvent(SensorEvent event) { + log.debug("hadoop set up policy recieved {}", event); + if (event.getValue() != null) { + setupMachine(event.getSource()); + } + }}); + } + + public void setupMachine(Entity e) { + try { + if (log.isDebugEnabled()) log.debug("setting up machine for hadoop at {}", e); + if (!e.getAttribute(Startable.SERVICE_UP)) return; + if (!configuredIds.add(e.getId())) return; + SshMachineLocation ssh = (SshMachineLocation) Iterables.getOnlyElement(e.getLocations()); + // TODO would prefer to extract content from HadoopNameNodeClusterActionHandler (but that class would need refactoring) + ssh.copyTo(new File(System.getProperty("user.home")+"/.whirr/"+hadoopCluster.getClusterSpec().getClusterName()+"/hadoop-site.xml"), "/tmp/hadoop-site.xml"); + + File identity = hadoopCluster.getClusterSpec().getPrivateKeyFile(); + if (identity == null){ + identity = File.createTempFile("hadoop", "key"); + identity.deleteOnExit(); + Files.write(hadoopCluster.getClusterSpec().getPrivateKey(), identity, Charsets.UTF_8); + } + if (log.isDebugEnabled()) log.debug("http config update for {}, identity file: {}", e, identity); + ssh.copyTo(identity, "/tmp/hadoop-proxy-private-key"); + + //copied from HadoopProxy, would prefer to reference (but again refactoring there is needed) + String user = hadoopCluster.getClusterSpec().getClusterUser(); + InetAddress namenode = HadoopCluster.getNamenodePublicAddress(hadoopCluster.getCluster()); + String server = namenode.getHostName(); + String proxyCommand = Joiner.on(" ").join(ImmutableList.of( + "ssh", + "-i", "/tmp/hadoop-proxy-private-key", + "-o", "ConnectTimeout=10", + "-o", "ServerAliveInterval=60", + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking=no", + "-N", + "-D 6666", + String.format("%s@%s", user, server))); + if (log.isDebugEnabled()) log.debug("http config update for {}, proxy command: {}", e, proxyCommand); + + String hadoopProxyForeverContent = + "while [ true ] ; do"+"\n"+ + " date"+"\n"+ + " echo starting proxy for hadoop to "+String.format("%s@%s", user, server)+"\n"+ + " nohup "+proxyCommand+"\n"+ + " echo proxy ended"+"\n"+ + "done"+"\n"; + + ssh.copyTo(new StringReader(hadoopProxyForeverContent), "/tmp/hadoop-proxy-forever.sh"); + + ssh.run("chmod 600 /tmp/hadoop-proxy-private-key ; chmod +x /tmp/hadoop-proxy-forever.sh ; nohup /tmp/hadoop-proxy-forever.sh &"); + + URI updateConfigUri = new URI(e.getAttribute(JBoss7Server.ROOT_URL)+ + "configure.jsp?key=brooklyn.example.hadoop.site.xml.url&value=file:///tmp/hadoop-site.xml"); + + HttpPollValue result = executeGet(updateConfigUri); + if (log.isDebugEnabled()) log.debug("http config update for {} got: {}, {}", new Object[] {e, result.getResponseCode(), new String(result.getContent())}); + } catch (Exception err) { + log.warn("unable to configure "+e+" for hadoop", err); + configuredIds.remove(e.getId()); + } + } + + private HttpPollValue executeGet(URI uri) throws ClientProtocolException, IOException { + DefaultHttpClient httpClient = new DefaultHttpClient(); + HttpGet httpGet = new HttpGet(uri); + HttpResponse httpResponse = httpClient.execute(httpGet); + try { + return new HttpPollValue(httpResponse); + } finally { + EntityUtils.consume(httpResponse.getEntity()); + } + } + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", Joiner.on(",").join(DEFAULT_LOCATIONS)); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + List locs = new LocationRegistry().getLocationsById(ImmutableList.of(location)); + + StartableApplication app = server.getManagementContext().getEntityManager().createEntity(BasicEntitySpec.newInstance(StartableApplication.class) + .displayName("Brooklyn Global Web Fabric with Hadoop Example") + .impl(WebFabricWithHadoopExample.class)); + Entities.startManagement(app, server.getManagementContext()); + + log.info("starting WebFabricWithHadoop, locations {}, mgmt on port {}", locs, port); + app.start(locs); + + Entities.dumpInfo(app); + } +} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrExample.groovy b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrExample.groovy deleted file mode 100644 index 1e0dd6d..0000000 --- a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrExample.groovy +++ /dev/null @@ -1,53 +0,0 @@ -package brooklyn.extras.whirr - -import java.util.List; - -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.Entities; - -import org.slf4j.LoggerFactory -import org.slf4j.Logger -import brooklyn.launcher.BrooklynLauncher -import brooklyn.location.Location; -import brooklyn.location.basic.CommandLineLocations -import brooklyn.location.basic.FixedListMachineProvisioningLocation; -import brooklyn.location.basic.LocalhostMachineProvisioningLocation; -import brooklyn.util.CommandLineUtil; -import brooklyn.extras.whirr.core.WhirrCluster - -public class WhirrExample extends AbstractApplication { - - private static final Logger LOG = LoggerFactory.getLogger(WhirrExample.class); - - public static final List DEFAULT_LOCATIONS = [ "aws-ec2:eu-west-1" ] - - public static final String RECIPE = ''' -whirr.cluster-name=brooklyn-whirr -whirr.hardware-min-ram=1024 -whirr.instance-templates=1 noop, 1 elasticsearch -''' - - WhirrCluster cluster = new WhirrCluster(this, recipe: RECIPE) - - public static void main(String[] argv) { - ArrayList args = new ArrayList(Arrays.asList(argv)); - int port = CommandLineUtil.getCommandLineOptionInt(args, "--port", 8081); - List locations = CommandLineLocations.getLocationsById(args ?: DEFAULT_LOCATIONS) - - try { - def app = new WhirrExample() - - BrooklynLauncher.manage(app, port) - app.start(locations) - Entities.dumpInfo(app) - LOG.info("Press return to shut down the cluster") - System.in.read() //wait for the user to type a key - app.stop() - } catch (Throwable e) { - LOG.error("Failed to start: "+e, e); - Thread.sleep(600); - throw e; - } - } - -} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrExample.java b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrExample.java new file mode 100644 index 0000000..0a44d6d --- /dev/null +++ b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrExample.java @@ -0,0 +1,59 @@ +package brooklyn.extras.whirr; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.extras.whirr.core.WhirrCluster; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.util.CommandLineUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +public class WhirrExample extends ApplicationBuilder { + + private static final Logger LOG = LoggerFactory.getLogger(WhirrExample.class); + + public static final String DEFAULT_LOCATION = "aws-ec2:eu-west-1"; + + public static final String RECIPE = + "whirr.cluster-name=brooklyn-whirr"+"\n"+ + "whirr.hardware-min-ram=1024"+"\n"+ + "whirr.instance-templates=1 noop, 1 elasticsearch"+"\n"; + + protected void doBuild() { + WhirrCluster cluster = createChild(BasicEntitySpec.newInstance(WhirrCluster.class) + .configure("recipe", RECIPE)); + } + + public static void main(String[] argv) throws Exception { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new WhirrExample() + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + + LOG.info("Press return to shut down the cluster"); + System.in.read(); //wait for the user to type a key + app.stop(); + } +} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrHadoopExample.groovy b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrHadoopExample.groovy deleted file mode 100644 index 5d0d620..0000000 --- a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrHadoopExample.groovy +++ /dev/null @@ -1,38 +0,0 @@ -package brooklyn.extras.whirr - -import java.util.List; - -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.Entities; -import brooklyn.extras.whirr.core.WhirrCluster -import brooklyn.launcher.BrooklynLauncher -import brooklyn.location.Location; -import brooklyn.location.basic.CommandLineLocations -import brooklyn.location.basic.LocationRegistry; -import brooklyn.util.CommandLineUtil; - -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import brooklyn.extras.whirr.hadoop.WhirrHadoopCluster - -public class WhirrHadoopExample extends AbstractApplication { - - private static final Logger LOG = LoggerFactory.getLogger(WhirrHadoopExample.class); - - public static final String DEFAULT_LOCATION = "aws-ec2:eu-west-1" - - WhirrCluster cluster = new WhirrHadoopCluster(this, size: 2, memory: 2048, name: "brooklyn-hadoop-example") - - public static void main(String[] argv) { - ArrayList args = new ArrayList(Arrays.asList(argv)); - int port = CommandLineUtil.getCommandLineOptionInt(args, "--port", 8081); - List locations = new LocationRegistry().getLocationsById(args ?: [DEFAULT_LOCATION]) - - def app = new WhirrHadoopExample() - - BrooklynLauncher.manage(app, port) - app.start(locations) - Entities.dumpInfo(app) - } - -} diff --git a/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrHadoopExample.java b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrHadoopExample.java new file mode 100644 index 0000000..104d716 --- /dev/null +++ b/hadoop-and-whirr/src/main/java/brooklyn/extras/whirr/WhirrHadoopExample.java @@ -0,0 +1,58 @@ +package brooklyn.extras.whirr; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.extras.whirr.core.WhirrCluster; +import brooklyn.extras.whirr.hadoop.WhirrHadoopCluster; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.util.CommandLineUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +public class WhirrHadoopExample extends ApplicationBuilder { + + private static final Logger LOG = LoggerFactory.getLogger(WhirrHadoopExample.class); + + public static final String DEFAULT_LOCATION = "aws-ec2:eu-west-1"; + + @Override + protected void doBuild() { + WhirrCluster cluster = createChild(BasicEntitySpec.newInstance(WhirrHadoopCluster.class) + .displayName("brooklyn-hadoop-example") + .configure("size", 2) + .configure("memory", 2048)); + } + + public static void main(String[] argv) throws Exception { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new WhirrHadoopExample() + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + + LOG.info("Press return to shut down the cluster"); + System.in.read(); //wait for the user to type a key + app.stop(); + } +} diff --git a/monitored-cassandra-cluster/.gitignore b/monitored-cassandra-cluster/.gitignore new file mode 100644 index 0000000..7a8040d --- /dev/null +++ b/monitored-cassandra-cluster/.gitignore @@ -0,0 +1 @@ +resources/lib/ \ No newline at end of file diff --git a/monitored-cassandra-cluster/README.txt b/monitored-cassandra-cluster/README.txt new file mode 100644 index 0000000..6048867 --- /dev/null +++ b/monitored-cassandra-cluster/README.txt @@ -0,0 +1,24 @@ +Instructions for running examples +================================= + +The commands below assume that the `brooklyn` script is already on your $PATH, and you are in the "examples" directory: + + cd simple-messaging-pubsub + export BROOKLYN_CLASSPATH=$(pwd)/target/classes + + # Launches a qpid broker on localhost + brooklyn -v launch --app brooklyn.demo.StandaloneBrokerExample --location localhost + + # You can get the broker's URL from the brooklyn web-console at http://localhost:8081 + # by looking at the broker entity's sensors or from the verbose output from the application startup + URL="amqp://guest:guest@/localhost?brokerlist='tcp://localhost:5672'" + + # Test subscribing, to receive a message from the broker + java -cp "./resources/lib/*:./target/classes" brooklyn.demo.Subscribe ${URL} + + # Test publishing a message to the broker + java -cp "./resources/lib/*:./target/classes" brooklyn.demo.Publish ${URL} + +--- + +For more information, please visit: http://brooklyncentral.github.com/use/examples/messaging/ diff --git a/monitored-cassandra-cluster/pom.xml b/monitored-cassandra-cluster/pom.xml new file mode 100644 index 0000000..3649e91 --- /dev/null +++ b/monitored-cassandra-cluster/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + jar + brooklyn-example-monitored-cassandra-cluster + Brooklyn Cassandra Cluster with Monitoring Example + + + io.brooklyn.example + brooklyn-examples-parent + 0.5.0-SNAPSHOT + ../pom.xml + + + + + io.brooklyn + brooklyn-all + ${project.version} + provided + + + + com.google.guava + guava + + + + + + + maven-clean-plugin + + + + ${project.basedir} + + ${project.artifactId}/ + brooklyn*.log + brooklyn*.log.* + stacktrace.log + resources/lib/ + + + + + + + + diff --git a/monitored-cassandra-cluster/src/main/java/brooklyn/demo/MonitoredCassandraClusterExample.groovy b/monitored-cassandra-cluster/src/main/java/brooklyn/demo/MonitoredCassandraClusterExample.groovy new file mode 100644 index 0000000..df7fe9d --- /dev/null +++ b/monitored-cassandra-cluster/src/main/java/brooklyn/demo/MonitoredCassandraClusterExample.groovy @@ -0,0 +1,27 @@ +package brooklyn.demo + +import java.util.List + +import brooklyn.entity.basic.AbstractApplication +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.nosql.cassandra.CassandraCluster +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.jboss.JBoss7Server; +import brooklyn.location.Location + +/** Cassandra Application */ +public class MonitoredCassandraClusterExample extends ApplicationBuilder { + + /** + * For overriding, to create and wire together entities. + */ + protected void doBuild() { + createChild(BasicEntitySpec.newInstance(CassandraCluster.class) + .configure("initialSize", "2") + .configure("clusterName", "CassandraDemo") + .configure("jmxPort", "11099+") + .configure("rmiServerPort", "9001+") + .configure("thriftPort", "9160+")); + } + +} diff --git a/monitored-cassandra-cluster/src/main/resources/logback.xml b/monitored-cassandra-cluster/src/main/resources/logback.xml new file mode 100644 index 0000000..25f3755 --- /dev/null +++ b/monitored-cassandra-cluster/src/main/resources/logback.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/pom.xml b/pom.xml index 6c29dd4..46aab45 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,17 @@ ../pom.xml + + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + false + true + + + webapps simple-web-cluster @@ -26,6 +37,7 @@ hadoop-and-whirr portable-cloudfoundry simple-messaging-pubsub + monitored-cassandra-cluster diff --git a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableCloudFoundryClusterExample.groovy b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableCloudFoundryClusterExample.groovy deleted file mode 100644 index c3394fe..0000000 --- a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableCloudFoundryClusterExample.groovy +++ /dev/null @@ -1,35 +0,0 @@ -package brooklyn.example.cloudfoundry; - -import groovy.transform.InheritConstructors -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.Entities -import brooklyn.launcher.BrooklynLauncher -import brooklyn.location.Location -import brooklyn.location.basic.LocationRegistry -import brooklyn.util.CommandLineUtil - -@InheritConstructors -public class MovableCloudFoundryClusterExample extends AbstractApplication implements MovableEntityTrait { - - public static final String DEFAULT_LOCATION = "cloudfoundry" - public static final String WAR_FILE_URL = "classpath://hello-world-webapp.war"; - - MovableElasticWebAppCluster websvc = new MovableElasticWebAppCluster(this, war: WAR_FILE_URL); - - @Override - public String move(String location) { - websvc.move(location); - } - - public static void main(String[] argv) { - ArrayList args = new ArrayList(Arrays.asList(argv)); - int port = CommandLineUtil.getCommandLineOptionInt(args, "--port", 8081); - List locations = new LocationRegistry().getLocationsById(args ?: [DEFAULT_LOCATION]) - - MovableCloudFoundryClusterExample app = new MovableCloudFoundryClusterExample(name:'Movable Web Cluster') - - BrooklynLauncher.manage(app, port) - app.start(locations) - Entities.dumpInfo(app) - } -} diff --git a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableCloudFoundryClusterExample.java b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableCloudFoundryClusterExample.java new file mode 100644 index 0000000..85374a2 --- /dev/null +++ b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableCloudFoundryClusterExample.java @@ -0,0 +1,47 @@ +package brooklyn.example.cloudfoundry; + +import java.util.List; + +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.util.CommandLineUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +public class MovableCloudFoundryClusterExample extends ApplicationBuilder { + + public static final String DEFAULT_LOCATION = "cloudfoundry"; + public static final String WAR_FILE_URL = "classpath://hello-world-webapp.war"; + + @Override + protected void doBuild() { + createChild(BasicEntitySpec.newInstance(MovableElasticWebAppCluster.class) + .configure("war", WAR_FILE_URL)); + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new MovableCloudFoundryClusterExample() + .appDisplayName("Movable Web Cluster") + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } +} diff --git a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppCluster.java b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppCluster.java new file mode 100644 index 0000000..fc2f76b --- /dev/null +++ b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppCluster.java @@ -0,0 +1,57 @@ +package brooklyn.example.cloudfoundry; + +import java.util.Collection; + +import brooklyn.entity.Effector; +import brooklyn.entity.Entity; +import brooklyn.entity.basic.Description; +import brooklyn.entity.basic.MethodEffector; +import brooklyn.entity.basic.NamedParameter; +import brooklyn.entity.proxying.ImplementedBy; +import brooklyn.entity.trait.Startable; +import brooklyn.entity.webapp.JavaWebAppService; +import brooklyn.event.basic.BasicAttributeSensor; +import brooklyn.event.basic.BasicConfigKey; +import brooklyn.util.flags.SetFromFlag; + +@ImplementedBy(MovableElasticWebAppClusterImpl.class) +public interface MovableElasticWebAppCluster extends Entity, Startable, MovableEntityTrait { + + // this advertises that this config key is easily available on this entity, + // either by passing (war: "classpath://...") in the constructor or by setConfig(ROOT_WAR). + // as a config variable, it will be inherited by children, so the children web app entities will pick it up. + @SetFromFlag("war") + public static final BasicConfigKey ROOT_WAR = JavaWebAppService.ROOT_WAR; + + @SetFromFlag("ttl") + public static final BasicConfigKey TIME_TO_LIVE_SECONDS = new BasicConfigKey( + Long.class, "movable.time.to.live", "Time to keep demoted cluster alive (should exceed GeoDNS TTL; default 0)", 0L); + + public static final BasicAttributeSensor PRIMARY_SVC_ENTITY_ID = new BasicAttributeSensor( + String.class, "movable.primary.id", "Entity ID of primary web-app service"); + + public static final BasicAttributeSensor> SECONDARY_SVC_ENTITY_IDS = new BasicAttributeSensor( + Collection.class, "movable.secondary.ids", "Entity IDs of secondary web-app services"); + + public static final Effector CREATE_SECONDARY_IN_LOCATION = new MethodEffector(MovableElasticWebAppCluster.class, "createSecondaryInLocation"); + public static final Effector PROMOTE_SECONDARY = new MethodEffector(MovableElasticWebAppCluster.class, "promoteSecondary"); + public static final Effector DESTROY_SECONDARY = new MethodEffector(MovableElasticWebAppCluster.class, "destroySecondary"); + + /** creates a new secondary instance, in the given location, returning the ID of the secondary created and started */ + @Description("create a new secondary instance in the given location") + public String createSecondaryInLocation( + @NamedParameter("location") @Description("the location where to start the secondary") String l); + + /** promotes the indicated secondary, + * returning the ID of the former-primary which has been demoted */ + @Description("promote the indicated secondary to primary (demoting the existing primary)") + public String promoteSecondary( + @NamedParameter("idOfSecondaryToPromote") @Description("ID of secondary entity to promote") + String idOfSecondaryToPromote); + + /** destroys the indicated secondary */ + @Description("destroy the indicated secondary") + public void destroySecondary( + @NamedParameter("idOfSecondaryToDestroy") @Description("ID of secondary entity to destroy") + String idOfSecondaryToDestroy); +} diff --git a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppCluster.groovy b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppClusterImpl.groovy similarity index 52% rename from portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppCluster.groovy rename to portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppClusterImpl.groovy index 1be85d9..77508a8 100644 --- a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppCluster.groovy +++ b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableElasticWebAppClusterImpl.groovy @@ -1,49 +1,33 @@ package brooklyn.example.cloudfoundry -import groovy.lang.MetaClass -import groovy.transform.InheritConstructors - -import java.util.Collection - import org.slf4j.Logger import org.slf4j.LoggerFactory -import brooklyn.enricher.basic.SensorPropagatingEnricher; import brooklyn.entity.Effector import brooklyn.entity.Entity import brooklyn.entity.basic.AbstractEntity -import brooklyn.entity.basic.Description import brooklyn.entity.basic.Entities import brooklyn.entity.basic.EntityLocal -import brooklyn.entity.basic.MethodEffector -import brooklyn.entity.basic.NamedParameter import brooklyn.entity.trait.Startable import brooklyn.entity.trait.StartableMethods import brooklyn.entity.webapp.ElasticJavaWebAppService -import brooklyn.entity.webapp.JavaWebAppService -import brooklyn.event.basic.BasicAttributeSensor -import brooklyn.event.basic.BasicConfigKey import brooklyn.location.Location import brooklyn.location.basic.LocationRegistry -import brooklyn.util.flags.SetFromFlag +import brooklyn.util.task.Tasks import com.google.common.collect.Iterables -@InheritConstructors -class MovableElasticWebAppCluster extends AbstractEntity implements Startable, MovableEntityTrait { +public class MovableElasticWebAppClusterImpl extends AbstractEntity implements MovableElasticWebAppCluster { - public static final Logger log = LoggerFactory.getLogger(MovableElasticWebAppCluster.class); + public static final Logger log = LoggerFactory.getLogger(MovableElasticWebAppClusterImpl.class); - // this advertises that this config key is easily available on this entity, - // either by passing (war: "classpath://...") in the constructor or by setConfig(ROOT_WAR). - // as a config variable, it will be inherited by children, so the children web app entities will pick it up. - @SetFromFlag("war") - public static final BasicConfigKey ROOT_WAR = JavaWebAppService.ROOT_WAR; + public MovableElasticWebAppClusterImpl() { + } - public static final BasicAttributeSensor PRIMARY_SVC_ENTITY_ID = - [ String, "movable.primary.id", "Entity ID of primary web-app service" ]; - public static final BasicAttributeSensor> SECONDARY_SVC_ENTITY_IDS = - [ Collection, "movable.secondary.ids", "Entity IDs of secondary web-app services" ]; + @Deprecated // use EntityManager.createEntity() or ApplicationBuilder.createChild() + public MovableElasticWebAppClusterImpl(Map flags, Entity parent) { + super(flags, parent); + } @Override public void start(Collection locations) { @@ -61,9 +45,11 @@ class MovableElasticWebAppCluster extends AbstractEntity implements Startable, M public EntityLocal createClusterIn(Location location) { //TODO the policy // app.web.cluster.addPolicy(app.policy) - return new ElasticJavaWebAppService.Factory(). - newFactoryForLocation(location). - newEntity([:], this); + EntityLocal result = new ElasticJavaWebAppService.Factory() + .newFactoryForLocation(location) + .newEntity([:], this); + Entities.manage(result); + return result; } @Override @@ -82,28 +68,17 @@ class MovableElasticWebAppCluster extends AbstractEntity implements Startable, M * then destroying the old-primary-now-secondary (X) */ - public static final Effector CREATE_SECONDARY_IN_LOCATION = new MethodEffector(this.&createSecondaryInLocation); - public static final Effector PROMOTE_SECONDARY = new MethodEffector(this.&promoteSecondary); - public static final Effector DESTROY_SECONDARY = new MethodEffector(this.&destroySecondary); - - /** creates a new secondary instance, in the given location, returning the ID of the secondary created and started */ - @Description("create a new secondary instance in the given location") - public String createSecondaryInLocation( - @NamedParameter("location") @Description("the location where to start the secondary") - String l) { + @Override + public String createSecondaryInLocation(String l) { Location location = new LocationRegistry().resolve(l); Entity svc = createClusterIn(location); - Entities.start(managementContext, svc, [location]); + Entities.start(svc, [location]); setAttribute(SECONDARY_SVC_ENTITY_IDS, (getAttribute(SECONDARY_SVC_ENTITY_IDS) ?: []) + svc.id); return svc.id; } - /** promotes the indicated secondary, - * returning the ID of the former-primary which has been demoted */ - @Description("promote the indicated secondary to primary (demoting the existing primary)") - public String promoteSecondary( - @NamedParameter("idOfSecondaryToPromote") @Description("ID of secondary entity to promote") - String idOfSecondaryToPromote) { + @Override + public String promoteSecondary(String idOfSecondaryToPromote) { Collection currentSecondaryIds = getAttribute(SECONDARY_SVC_ENTITY_IDS) if (!currentSecondaryIds.contains(idOfSecondaryToPromote)) throw new IllegalStateException("Cannot promote unknown secondary $idOfSecondaryToPromote "+ @@ -118,11 +93,8 @@ class MovableElasticWebAppCluster extends AbstractEntity implements Startable, M return primaryId; } - /** destroys the indicated secondary */ - @Description("destroy the indicated secondary") - public void destroySecondary( - @NamedParameter("idOfSecondaryToDestroy") @Description("ID of secondary entity to destroy") - String idOfSecondaryToDestroy) { + @Override + public void destroySecondary(String idOfSecondaryToDestroy) { Collection currentSecondaryIds = getAttribute(SECONDARY_SVC_ENTITY_IDS) if (!currentSecondaryIds.contains(idOfSecondaryToDestroy)) throw new IllegalStateException("Cannot promote unknown secondary $idOfSecondaryToDestroy "+ @@ -131,14 +103,17 @@ class MovableElasticWebAppCluster extends AbstractEntity implements Startable, M currentSecondaryIds.remove(idOfSecondaryToDestroy); setAttribute(SECONDARY_SVC_ENTITY_IDS, currentSecondaryIds); - Entity secondary = getManagementContext().getEntityManager().getEntity(idOfSecondaryToDestroy); - Entities.destroy(managementContext, secondary); + Entity secondary = getEntityManager().getEntity(idOfSecondaryToDestroy); + Entities.destroy(secondary); } @Override public String move(String location) { String newPrimary = createSecondaryInLocation(location); String oldPrimary = promoteSecondary(newPrimary); + long ttl = getConfig(TIME_TO_LIVE_SECONDS); + if (ttl>0) + Tasks.withBlockingDetails("waiting for TTL to destroy old primary") { Thread.sleep(ttl*1000); } destroySecondary(oldPrimary); return newPrimary; } diff --git a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTrait.groovy b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTrait.groovy deleted file mode 100644 index 7434583..0000000 --- a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTrait.groovy +++ /dev/null @@ -1,21 +0,0 @@ -package brooklyn.example.cloudfoundry; - -import brooklyn.entity.Effector -import brooklyn.entity.basic.Description -import brooklyn.entity.basic.MethodEffector -import brooklyn.entity.basic.NamedParameter - -public interface MovableEntityTrait { - - Effector MOVE = new MethodEffector(MovableEntityTrait.&move); - - /** Effectively move the entity to the new location. - * A new entity may be created (and the old destroyed) to effect this. - * @param location the new location where the entity should running - * @return the entity ID of the primary entity (after the move) in the specified location */ - @Description("Effectively move the entity to the new location.") - public String move( - @NamedParameter("location") @Description("The new location where the entity should be running") - String location); - -} diff --git a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTraitAlt.java b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTrait.java similarity index 80% rename from portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTraitAlt.java rename to portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTrait.java index 1013810..5f5afe2 100644 --- a/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTraitAlt.java +++ b/portable-cloudfoundry/src/main/java/brooklyn/example/cloudfoundry/MovableEntityTrait.java @@ -5,13 +5,9 @@ import brooklyn.entity.basic.MethodEffector; import brooklyn.entity.basic.NamedParameter; -/** - * This defines an identical ``move`` effector as MovableEntityTrait, - * but shows examples of a pure-java syntax. - */ -public interface MovableEntityTraitAlt { +public interface MovableEntityTrait { - Effector MOVE = new MethodEffector(MovableEntityTraitAlt.class, "move"); + Effector MOVE = new MethodEffector(MovableEntityTrait.class, "move"); /** Effectively move the entity to the new location. * A new entity may be created (and the old destroyed) to effect this. diff --git a/simple-messaging-pubsub/src/main/java/brooklyn/demo/StandaloneBrokerExample.groovy b/simple-messaging-pubsub/src/main/java/brooklyn/demo/StandaloneBrokerExample.groovy deleted file mode 100644 index 329825f..0000000 --- a/simple-messaging-pubsub/src/main/java/brooklyn/demo/StandaloneBrokerExample.groovy +++ /dev/null @@ -1,27 +0,0 @@ -package brooklyn.demo - -import java.util.List - -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.messaging.amqp.AmqpServer -import brooklyn.entity.messaging.qpid.QpidBroker -import brooklyn.location.Location - -/** Qpid Broker Application */ -public class StandaloneBrokerExample extends AbstractApplication { - - public static final String CUSTOM_CONFIG_PATH = "classpath://custom-config.xml" - public static final String PASSWD_PATH = "classpath://passwd" - public static final String QPID_BDBSTORE_JAR_PATH = "classpath://qpid-bdbstore-0.14.jar" - public static final String BDBSTORE_JAR_PATH = "classpath://je-5.0.34.jar" - - // Configure the Qpid broker entity - QpidBroker broker = new QpidBroker(this, - amqpPort:5672, - amqpVersion:AmqpServer.AMQP_0_10, - runtimeFiles:[ (QpidBroker.CONFIG_XML):CUSTOM_CONFIG_PATH, - (QpidBroker.PASSWD):PASSWD_PATH, - ("lib/opt/qpid-bdbstore-0.14.jar"):QPID_BDBSTORE_JAR_PATH, - ("lib/opt/je-5.0.34.jar"):BDBSTORE_JAR_PATH ], - queue:"testQueue") -} diff --git a/simple-messaging-pubsub/src/main/java/brooklyn/demo/StandaloneBrokerExample.java b/simple-messaging-pubsub/src/main/java/brooklyn/demo/StandaloneBrokerExample.java new file mode 100644 index 0000000..602a26c --- /dev/null +++ b/simple-messaging-pubsub/src/main/java/brooklyn/demo/StandaloneBrokerExample.java @@ -0,0 +1,63 @@ +package brooklyn.demo; + +import java.util.List; + +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.messaging.amqp.AmqpServer; +import brooklyn.entity.messaging.qpid.QpidBroker; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.util.CommandLineUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; + +/** Qpid Broker Application */ +public class StandaloneBrokerExample extends ApplicationBuilder { + + public static final String CUSTOM_CONFIG_PATH = "classpath://custom-config.xml"; + public static final String PASSWD_PATH = "classpath://passwd"; + public static final String QPID_BDBSTORE_JAR_PATH = "classpath://qpid-bdbstore-0.14.jar"; + public static final String BDBSTORE_JAR_PATH = "classpath://je-5.0.34.jar"; + + public static final String DEFAULT_LOCATION = "localhost"; + + protected void doBuild() { + // Configure the Qpid broker entity + QpidBroker broker = createChild(BasicEntitySpec.newInstance(QpidBroker.class) + .configure("amqpPort", 5672) + .configure("amqpVersion", AmqpServer.AMQP_0_10) + .configure("runtimeFiles", ImmutableMap.builder() + .put(QpidBroker.CONFIG_XML, CUSTOM_CONFIG_PATH) + .put(QpidBroker.PASSWD, PASSWD_PATH) + .put("lib/opt/qpid-bdbstore-0.14.jar", QPID_BDBSTORE_JAR_PATH) + .put("lib/opt/je-5.0.34.jar", BDBSTORE_JAR_PATH) + .build()) + .configure("queue", "testQueue")); + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new StandaloneBrokerExample() + .appDisplayName("Qpid app") + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } +} diff --git a/simple-open-loop-policy/README.txt b/simple-open-loop-policy/README.txt new file mode 100644 index 0000000..65fb390 --- /dev/null +++ b/simple-open-loop-policy/README.txt @@ -0,0 +1,55 @@ +Instructions for Running Examples +================================= + +The commands below assume that the `brooklyn` script is on your $PATH, this project has been built, +and you are in this directory. Adjust to taste for other configurations. + + export BROOKLYN_CLASSPATH=$(pwd)/target/classes + + # Three-tier: auto-scaling app-server cluster fronted by nginx, MySql backend wired up, on localhost + brooklyn launch --app brooklyn.demo.WebClusterDatabaseOpenLoopExample --location localhost + +The above requires passwordless `ssh localhost` and requires `gcc` to build `nginx`. +You could instead target your favourite cloud, where this has been tried and tested: + + +Redistributable embedded example: + + # To build a redistributable tar.gz with a start.sh script + # which invokes the `main` method in the example class to start + # (the redistributable will be at: target/brooklyn-*-bin.tar.gz ) + mvn clean assembly:assembly + +For more information, please visit: + + http://brooklyncentral.github.com/use/examples/webcluster/ + + +Developer Notes +=============== + +This example sends an SMS message when the cluster has reached its max size (and where the auto-scaler policy +would continue to increase the size if it were not capped). The message is sent using clickatell.com, +using http://smsj.sourceforge.net. + +Because smsj is not available on maven central, a custom local maven repo has been built (and checked in to git): + + wget http://sourceforge.net/projects/smsj/files/smsj/smsj-snapshot-20051126/smsj-20051126.jar/download + + mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file \ + -Dfile=smsj-20051126.jar \ + -DgroupId=io.brooklyn \ + -DartifactId=org.marre.smsj \ + -Dversion=1.0.0-20051126 \ + -Dpackaging=jar \ + -DlocalRepositoryPath=localrepo + +And in the pom, this local repo is referenced: + + + + brooklyn-examples-localrepo + file://${basedir}/localrepo + + + diff --git a/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/1.0.0-20051126/org.marre.smsj-1.0.0-20051126.jar b/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/1.0.0-20051126/org.marre.smsj-1.0.0-20051126.jar new file mode 100644 index 0000000..a076a47 Binary files /dev/null and b/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/1.0.0-20051126/org.marre.smsj-1.0.0-20051126.jar differ diff --git a/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/1.0.0-20051126/org.marre.smsj-1.0.0-20051126.pom b/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/1.0.0-20051126/org.marre.smsj-1.0.0-20051126.pom new file mode 100644 index 0000000..7361303 --- /dev/null +++ b/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/1.0.0-20051126/org.marre.smsj-1.0.0-20051126.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + io.brooklyn + org.marre.smsj + 1.0.0-20051126 + POM was created from install:install-file + diff --git a/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/maven-metadata-local.xml b/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/maven-metadata-local.xml new file mode 100644 index 0000000..4611327 --- /dev/null +++ b/simple-open-loop-policy/localrepo/io/brooklyn/org.marre.smsj/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + io.brooklyn + org.marre.smsj + + 1.0.0-20051126 + + 1.0.0-20051126 + + 20130206095028 + + diff --git a/simple-open-loop-policy/pom.xml b/simple-open-loop-policy/pom.xml new file mode 100644 index 0000000..ab5c816 --- /dev/null +++ b/simple-open-loop-policy/pom.xml @@ -0,0 +1,133 @@ + + 4.0.0 + jar + brooklyn-example-simple-open-loop-policy + Brooklyn Simple Web Cluster Example + + + + io.brooklyn.example + brooklyn-examples-parent + 0.5.0-SNAPSHOT + ../pom.xml + + + + + brooklyn-examples-localrepo + file://${basedir}/localrepo + + + + + + io.brooklyn + org.marre.smsj + 1.0.0-20051126 + + + io.brooklyn + brooklyn-all + ${project.version} + + + io.brooklyn + brooklyn-logback-xml + ${project.version} + true + + + + io.brooklyn + brooklyn-test-support + ${project.version} + test + + + + + + + maven-dependency-plugin + + + + copy + process-classes + + copy + + + + + + ${project.groupId} + brooklyn-example-hello-world-webapp + ${project.version} + war + true + target/classes + hello-world-webapp.war + + + ${project.groupId} + brooklyn-example-hello-world-sql-webapp + ${project.version} + war + true + target/classes + hello-world-sql-webapp.war + + + + + + + + + maven-clean-plugin + + + + ${project.basedir} + + ${project.artifactId}/ + brooklyn*.log + brooklyn*.log.* + stacktrace.log + + + + + + + + + + + + + diff --git a/simple-open-loop-policy/resources/jmeter-test-plan.jmx b/simple-open-loop-policy/resources/jmeter-test-plan.jmx new file mode 100644 index 0000000..5487b8f --- /dev/null +++ b/simple-open-loop-policy/resources/jmeter-test-plan.jmx @@ -0,0 +1,125 @@ + + + + + + false + false + + + + + + + + continue + + false + -1 + + 8 + 1 + 1326116677000 + 1326116677000 + false + + + + + + 20 + + + + + + + localhost + 8000 + + + + + + GET + true + false + true + false + false + + + + + + false + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + + + + + + diff --git a/simple-open-loop-policy/src/main/java/brooklyn/demo/Sms.java b/simple-open-loop-policy/src/main/java/brooklyn/demo/Sms.java new file mode 100644 index 0000000..abaa506 --- /dev/null +++ b/simple-open-loop-policy/src/main/java/brooklyn/demo/Sms.java @@ -0,0 +1,45 @@ +package brooklyn.demo; + +import java.io.IOException; + +import org.marre.SmsSender; +import org.marre.sms.SmsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Sms { + + private static final Logger LOG = LoggerFactory.getLogger(Sms.class); + + private final String username; + private final String password; + private final String apiid; + private final String sender; + + public Sms(String username, String password, String apiid) { + this.username = username; + this.password = password; + this.apiid = apiid; + this.sender = null; + } + + /** + * + * @param receiver International number to reciever without leading "+" + * @param msg The message that you want to send + * @throws IOException + * @throws SmsException + */ + public void sendSms(String receiver, String msg) throws SmsException, IOException { + // Send SMS with clickatell + SmsSender smsSender = SmsSender.getClickatellSender(username, password, apiid); + + smsSender.connect(); + try { + String msgid = smsSender.sendTextSms(msg, receiver, sender); + LOG.debug("Sent SMS via {}@clickatell to {}, msg {}; id {}", new Object[] {username, receiver, msg, msgid}); + } finally { + smsSender.disconnect(); + } + } +} diff --git a/simple-open-loop-policy/src/main/java/brooklyn/demo/WebClusterDatabaseOpenLoopExample.java b/simple-open-loop-policy/src/main/java/brooklyn/demo/WebClusterDatabaseOpenLoopExample.java new file mode 100644 index 0000000..3ac75e4 --- /dev/null +++ b/simple-open-loop-policy/src/main/java/brooklyn/demo/WebClusterDatabaseOpenLoopExample.java @@ -0,0 +1,141 @@ +package brooklyn.demo; + +import static brooklyn.entity.java.JavaEntityMethods.javaSysProp; +import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady; +import static brooklyn.event.basic.DependentConfiguration.formatString; + +import java.io.IOException; +import java.util.List; + +import org.marre.sms.SmsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.enricher.basic.SensorPropagatingEnricher; +import brooklyn.enricher.basic.SensorTransformingEnricher; +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.database.mysql.MySqlNode; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import brooklyn.entity.webapp.DynamicWebAppCluster; +import brooklyn.entity.webapp.JavaWebAppService; +import brooklyn.entity.webapp.WebAppService; +import brooklyn.entity.webapp.WebAppServiceConstants; +import brooklyn.event.SensorEvent; +import brooklyn.event.SensorEventListener; +import brooklyn.event.basic.BasicAttributeSensor; +import brooklyn.event.basic.BasicNotificationSensor; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.location.basic.PortRanges; +import brooklyn.policy.autoscaling.AutoScalerPolicy; +import brooklyn.policy.autoscaling.MaxPoolSizeReachedEvent; +import brooklyn.util.CommandLineUtil; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +/** + * Launches a 3-tier app with nginx, clustered jboss, and mysql. + **/ +public class WebClusterDatabaseOpenLoopExample extends ApplicationBuilder { + + public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseOpenLoopExample.class); + + public static final String WAR_PATH = "classpath://hello-world-sql-webapp.war"; + + public static final String DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql"; + + public static final String DB_TABLE = "visitors"; + public static final String DB_USERNAME = "brooklyn"; + public static final String DB_PASSWORD = "br00k11n"; + + // TODO Replace these with your details, for a clickatell.com account that has credit to send SMS messages + public static final String CLICKATELL_USERNAME = "brooklyndemo.uk"; + public static final String CLICKATELL_PASSWORD = "NAYLLHRLZEBYYA"; + public static final String CLICKATELL_APIID = "3411519"; + public static final String SMS_RECEIVER = "441234567890"; + + public static final BasicAttributeSensor APPSERVERS_COUNT = new BasicAttributeSensor(Integer.class, + "appservers.count", "Number of app servers deployed"); + + public static final BasicNotificationSensor MAX_SIZE_REACHED = new BasicNotificationSensor( + MaxPoolSizeReachedEvent.class, "cluster.maxPoolSizeReached", ""); + + protected void doBuild() { + MySqlNode mysql = createChild(BasicEntitySpec.newInstance(MySqlNode.class) + .configure("creationScriptUrl", DB_SETUP_SQL_URL)); + + ControlledDynamicWebAppCluster web = createChild(BasicEntitySpec.newInstance(ControlledDynamicWebAppCluster.class) + .configure(WebAppService.HTTP_PORT, PortRanges.fromString("8080+")) + .configure(JavaWebAppService.ROOT_WAR, WAR_PATH) + .configure(javaSysProp("brooklyn.example.db.url"), + formatString("jdbc:%s%s?user=%s\\&password=%s", + attributeWhenReady(mysql, MySqlNode.MYSQL_URL), + DB_TABLE, DB_USERNAME, DB_PASSWORD))); + + // Subscribe not notifications about the auto-scaler policy reaching its max cluster size + getManagementContext().getSubscriptionManager().subscribe( + web.getCluster(), + MAX_SIZE_REACHED, + new SensorEventListener() { + @Override public void onEvent(SensorEvent event) { + onMaxPoolSizeReached(event.getValue()); + } + }); + + // simple scaling policy + web.getCluster().addPolicy(AutoScalerPolicy.builder(). + metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE). + metricRange(10, 100). + sizeRange(1, 5). + maxSizeReachedSensor(MAX_SIZE_REACHED). +// maxReachedNotificationDelay(1000). + build()); + + // expose some KPI's + getApp().addEnricher(SensorPropagatingEnricher.newInstanceListeningTo(web, + WebAppServiceConstants.ROOT_URL, + DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW)); + getApp().addEnricher(new SensorTransformingEnricher(web, + DynamicWebAppCluster.GROUP_SIZE, APPSERVERS_COUNT, Functions.identity())); + } + + private void onMaxPoolSizeReached(MaxPoolSizeReachedEvent event) { + String msg = "Max-pool-size-reached: "+event; + System.out.println("*** "+msg); + + try { + new Sms(CLICKATELL_USERNAME, CLICKATELL_PASSWORD, CLICKATELL_APIID).sendSms(SMS_RECEIVER, msg); + } catch (SmsException e) { + LOG.warn("Error sending SMS message: "+e.getMessage(), e); + } catch (IOException e) { + LOG.warn("Error sending SMS message", e); + } + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", "localhost"); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new WebClusterDatabaseOpenLoopExample() + .appDisplayName("Brooklyn WebApp Cluster with Database example") + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } +} diff --git a/simple-open-loop-policy/src/main/resources/visitors-creation-script.sql b/simple-open-loop-policy/src/main/resources/visitors-creation-script.sql new file mode 100644 index 0000000..f3bdd4a --- /dev/null +++ b/simple-open-loop-policy/src/main/resources/visitors-creation-script.sql @@ -0,0 +1,17 @@ +create database visitors; +use visitors; +create user 'brooklyn' identified by 'br00k11n'; +grant usage on *.* to 'brooklyn'@'%' identified by 'br00k11n'; +# ''@localhost is sometimes set up, overriding brooklyn@'%', so do a second explicit grant +grant usage on *.* to 'brooklyn'@'localhost' identified by 'br00k11n'; +grant all privileges on visitors.* to 'brooklyn'@'%'; +flush privileges; + +CREATE TABLE MESSAGES ( + id INT NOT NULL AUTO_INCREMENT, + NAME VARCHAR(30) NOT NULL, + MESSAGE VARCHAR(400) NOT NULL, + PRIMARY KEY (ID) + ); + +INSERT INTO MESSAGES values (default, 'Isaac Asimov', 'I grew up in Brooklyn' ); diff --git a/simple-open-loop-policy/src/test/java/brooklyn/demo/SmsTest.java b/simple-open-loop-policy/src/test/java/brooklyn/demo/SmsTest.java new file mode 100644 index 0000000..486fbcc --- /dev/null +++ b/simple-open-loop-policy/src/test/java/brooklyn/demo/SmsTest.java @@ -0,0 +1,32 @@ +package brooklyn.demo; + +import org.marre.sms.SmsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +public class SmsTest { + + private static final Logger LOG = LoggerFactory.getLogger(SmsTest.class); + + @Test(groups="Integration") + public void testSendSms() throws Exception { + // http://api.clickatell.com/http/sendmsg?user=brooklyndemo.uk&password=PASSWORD&api_id=3411519&to=447709428472&text=Message + // Note this account has *no* credit card details; sending a message will result in a standard message from Clickatell.com, + // rather than receiving the actual message body. + // + // TODO It's started failing with "Error 301, No Credit Left" + // How to commit something that passes but without exposing credit card details?! + Sms sender = new Sms("brooklyndemo.uk", "NAYLLHRLZEBYYA", "3411519"); + try { + sender.sendSms("447709428472", "test sms sent in brooklyn"); + } catch (SmsException e) { + if (e.toString().contains("Error 301, No Credit Left")) { + // fair enough; let's not fail the test for this reason + LOG.warn("Cannot test SMS because no credit left on account: "+e.toString()); + } else { + throw e; + } + } + } +} diff --git a/simple-web-cluster/README.txt b/simple-web-cluster/README.txt index 19c13bc..0b238a4 100644 --- a/simple-web-cluster/README.txt +++ b/simple-web-cluster/README.txt @@ -27,8 +27,8 @@ Other examples: # A simple app: just load-balancer and appservers brooklyn launch --app brooklyn.demo.WebClusterExample --location localhost - # Pure Java three-tier example - brooklyn launch --app brooklyn.demo.WebClusterDatabaseExampleAltJava --location localhost + # Three-tier example + brooklyn launch --app brooklyn.demo.WebClusterDatabaseExample --location localhost Redistributable embedded example: diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.java b/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.java new file mode 100644 index 0000000..baf55fb --- /dev/null +++ b/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.java @@ -0,0 +1,64 @@ +package brooklyn.demo; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.jboss.JBoss7Server; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.util.CommandLineUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +/** This example starts one web app on 8080, waits for a keypress, then stops it. */ +public class SingleWebServerExample extends ApplicationBuilder { + + public static final Logger LOG = LoggerFactory.getLogger(SingleWebServerExample.class); + + public static final String DEFAULT_LOCATION = "localhost"; + + private static final String WAR_PATH = "classpath://hello-world-webapp.war"; + + @Override + protected void doBuild() { + createChild(BasicEntitySpec.newInstance(JBoss7Server.class) + .configure("war", WAR_PATH) + .configure("httpPort", 8080)); + } + + // Shows how to use ApplicationBuilder without sub-classing, but for CLI usage one should sub-class + public static void main(String[] argv) throws Exception { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + // TODO Want to parse, to handle multiple locations + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = ApplicationBuilder.builder() + .child(BasicEntitySpec.newInstance(JBoss7Server.class) + .configure("war", WAR_PATH) + .configure("httpPort", 8080)) + .manage(); + JBoss7Server web = (JBoss7Server) Iterables.getOnlyElement(app.getChildren()); + + LOG.info("created, now starting..."); + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + LOG.info("started, visit "+web.getAttribute(JBoss7Server.ROOT_URL)); + } +} diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.java b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.java new file mode 100644 index 0000000..e40c731 --- /dev/null +++ b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.java @@ -0,0 +1,109 @@ +package brooklyn.demo; + +import static brooklyn.entity.java.JavaEntityMethods.javaSysProp; +import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady; +import static brooklyn.event.basic.DependentConfiguration.formatString; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.enricher.basic.SensorPropagatingEnricher; +import brooklyn.enricher.basic.SensorTransformingEnricher; +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.database.mysql.MySqlNode; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import brooklyn.entity.webapp.DynamicWebAppCluster; +import brooklyn.entity.webapp.JavaWebAppService; +import brooklyn.entity.webapp.WebAppService; +import brooklyn.entity.webapp.WebAppServiceConstants; +import brooklyn.event.basic.BasicAttributeSensor; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.location.basic.PortRanges; +import brooklyn.policy.autoscaling.AutoScalerPolicy; +import brooklyn.util.CommandLineUtil; + +import com.google.common.base.Functions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +/** + * Launches a 3-tier app with nginx, clustered jboss, and mysql. + **/ +public class WebClusterDatabaseExample extends ApplicationBuilder { + + public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExample.class); + + public static final String WAR_PATH = "classpath://hello-world-sql-webapp.war"; + + public static final String DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql"; + + public static final String DB_TABLE = "visitors"; + public static final String DB_USERNAME = "brooklyn"; + public static final String DB_PASSWORD = "br00k11n"; + + public static final BasicAttributeSensor APPSERVERS_COUNT = new BasicAttributeSensor(Integer.class, + "appservers.count", "Number of app servers deployed"); + + protected void doBuild() { + MySqlNode mysql = createChild(BasicEntitySpec.newInstance(MySqlNode.class) + .configure("creationScriptUrl", DB_SETUP_SQL_URL)); + + ControlledDynamicWebAppCluster web = createChild(BasicEntitySpec.newInstance(ControlledDynamicWebAppCluster.class) + .configure(WebAppService.HTTP_PORT, PortRanges.fromString("8080+")) + .configure(JavaWebAppService.ROOT_WAR, WAR_PATH) + .configure(javaSysProp("brooklyn.example.db.url"), + formatString("jdbc:%s%s?user=%s\\&password=%s", + attributeWhenReady(mysql, MySqlNode.MYSQL_URL), + DB_TABLE, DB_USERNAME, DB_PASSWORD)) ); + + // simple scaling policy + web.getCluster().addPolicy(AutoScalerPolicy.builder(). + metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE). + metricRange(10, 100). + sizeRange(1, 5). + build()); + + // expose some KPI's + getApp().addEnricher(SensorPropagatingEnricher.newInstanceListeningTo(web, + WebAppServiceConstants.ROOT_URL, + DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW)); + getApp().addEnricher(new SensorTransformingEnricher(web, + DynamicWebAppCluster.GROUP_SIZE, APPSERVERS_COUNT, Functions.identity())); + } + + public static void main(String[] argv) { + // TODO want to crate a simpler way to do the boilerplate psv main; suggestion here: +// BrooklynApplicationCli cli = BrooklynApplicationCli.newInstance(). +// application(new WebClusterDatabaseExample() +// .appDisplayName("Brooklyn WebApp Cluster with Database example")). +// defaultLocations("localhost"). +// start(); +// +// Entities.dumpInfo(cli.getApplication()); + + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", "localhost"); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new WebClusterDatabaseExample() + .appDisplayName("Brooklyn WebApp Cluster with Database example") + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } +} diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleApp.java b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleApp.java new file mode 100644 index 0000000..36bf526 --- /dev/null +++ b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleApp.java @@ -0,0 +1,145 @@ +package brooklyn.demo; + +import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady; +import static brooklyn.event.basic.DependentConfiguration.formatString; + +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.catalog.CatalogConfig; +import brooklyn.config.ConfigKey; +import brooklyn.enricher.basic.SensorPropagatingEnricher; +import brooklyn.enricher.basic.SensorTransformingEnricher; +import brooklyn.entity.basic.AbstractApplication; +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.database.mysql.MySqlNode; +import brooklyn.entity.group.DynamicCluster; +import brooklyn.entity.java.JavaEntityMethods; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import brooklyn.entity.webapp.DynamicWebAppCluster; +import brooklyn.entity.webapp.JavaWebAppService; +import brooklyn.entity.webapp.WebAppService; +import brooklyn.entity.webapp.WebAppServiceConstants; +import brooklyn.event.AttributeSensor; +import brooklyn.event.basic.BasicAttributeSensor; +import brooklyn.event.basic.BasicConfigKey; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.location.basic.PortRanges; +import brooklyn.policy.autoscaling.AutoScalerPolicy; +import brooklyn.util.CommandLineUtil; + +import com.google.common.base.Functions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +/** + * Launches a 3-tier app with nginx, clustered jboss, and mysql. + *

+ * Demonstrates how to define a new Application Entity class (reusable and extensible), + * as opposed to just using the builder as in {@link WebClusterDatabaseExample}. + * With an app, when we define public static sensors and runtime config _on the app class_ + * (not the builder) they can be discovered at runtime. + *

+ * This variant also increases minimum size to 2. + * Note the policy min size must have the same value, + * otherwise it fights with cluster set up trying to reduce the cluster size! + **/ +public class WebClusterDatabaseExampleApp extends AbstractApplication implements StartableApplication { + + public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExampleApp.class); + + public static final String DEFAULT_LOCATION = "localhost"; + + public static final String DEFAULT_WAR_PATH = "classpath://hello-world-sql-webapp.war"; + + @CatalogConfig(label="WAR (URL)") + public static final ConfigKey WAR_PATH = new BasicConfigKey(String.class, + "app.war", "URL to the application archive which should be deployed", + DEFAULT_WAR_PATH); + + // TODO to expose in catalog we need to let the keystore url be specified (not hard) + // and also confirm that this works for nginx (might be a bit fiddly); + // booleans in the gui are working (With checkbox) +// @CatalogConfig(label="HTTPS") + public static final ConfigKey USE_HTTPS = new BasicConfigKey(Boolean.class, + "app.https", "Whether the application should use HTTPS only or just HTTP only (default)", false); + + public static final String DEFAULT_DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql"; + + @CatalogConfig(label="DB Setup SQL (URL)") + public static final ConfigKey DB_SETUP_SQL_URL = new BasicConfigKey(String.class, + "app.db_sql", "URL to the SQL script to set up the database", + DEFAULT_DB_SETUP_SQL_URL); + + public static final String DB_TABLE = "visitors"; + public static final String DB_USERNAME = "brooklyn"; + public static final String DB_PASSWORD = "br00k11n"; + + BasicAttributeSensor APPSERVERS_COUNT = new BasicAttributeSensor(Integer.class, + "appservers.count", "Number of app servers deployed"); + public static final AttributeSensor REQUESTS_PER_SECOND_IN_WINDOW = + WebAppServiceConstants.REQUESTS_PER_SECOND_IN_WINDOW; + public static final AttributeSensor ROOT_URL = WebAppServiceConstants.ROOT_URL; + + @Override + public void postConstruct() { + super.postConstruct(); + + MySqlNode mysql = (MySqlNode) addChild( + getEntityManager().createEntity( + BasicEntitySpec.newInstance(MySqlNode.class) + .configure(MySqlNode.CREATION_SCRIPT_URL, getConfig(DB_SETUP_SQL_URL))) ); + + ControlledDynamicWebAppCluster web = (ControlledDynamicWebAppCluster) addChild( + getEntityManager().createEntity( + BasicEntitySpec.newInstance(ControlledDynamicWebAppCluster.class) + .configure(WebAppService.HTTP_PORT, PortRanges.fromString("8080+")) + .configure(JavaWebAppService.ROOT_WAR, getConfig(WAR_PATH)) + .configure(JavaEntityMethods.javaSysProp("brooklyn.example.db.url"), + formatString("jdbc:%s%s?user=%s\\&password=%s", + attributeWhenReady(mysql, MySqlNode.MYSQL_URL), DB_TABLE, DB_USERNAME, DB_PASSWORD)) + .configure(DynamicCluster.INITIAL_SIZE, 2) + .configure(WebAppService.ENABLED_PROTOCOLS, Arrays.asList(getConfig(USE_HTTPS) ? "https" : "http")) )); + + web.getCluster().addPolicy(AutoScalerPolicy.builder(). + metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE). + metricRange(10, 100). + sizeRange(2, 5). + build()); + + addEnricher(SensorPropagatingEnricher.newInstanceListeningTo(web, + WebAppServiceConstants.ROOT_URL, + DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW)); + addEnricher(new SensorTransformingEnricher(web, + DynamicWebAppCluster.GROUP_SIZE, APPSERVERS_COUNT, Functions.identity())); + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = ApplicationBuilder.builder(WebClusterDatabaseExampleApp.class) + .displayName("Brooklyn WebApp Cluster with Database example") + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } + +} diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy new file mode 100644 index 0000000..722e1c0 --- /dev/null +++ b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy @@ -0,0 +1,87 @@ +package brooklyn.demo; + +import static brooklyn.entity.java.JavaEntityMethods.javaSysProp; +import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady; +import static brooklyn.event.basic.DependentConfiguration.formatString; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.database.mysql.MySqlNode; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import brooklyn.entity.webapp.DynamicWebAppCluster; +import brooklyn.entity.webapp.jboss.JBoss7Server; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.policy.autoscaling.AutoScalerPolicy; +import brooklyn.util.CommandLineUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +/** + * Launches a 3-tier app with nginx, clustered jboss, and mysql. + *

+ * This variant of {@link WebClusterDatabaseExample} demonstrates Groovy language conveniences. + **/ +public class WebClusterDatabaseExampleGroovy extends ApplicationBuilder { + + public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExampleGroovy.class); + + public static final String DEFAULT_LOCATION = "localhost"; + + public static final String WAR_PATH = "classpath://hello-world-sql-webapp.war"; + + public static final String DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql"; + + public static final String DB_TABLE = "visitors"; + public static final String DB_USERNAME = "brooklyn"; + public static final String DB_PASSWORD = "br00k11n"; + + protected void doBuild() { + MySqlNode mysql = createChild(MySqlNode, + creationScriptUrl: DB_SETUP_SQL_URL); + + ControlledDynamicWebAppCluster web = createChild(ControlledDynamicWebAppCluster, + war: WAR_PATH, + httpPort: "8080+", + (javaSysProp("brooklyn.example.db.url")): + formatString("jdbc:%s%s?user=%s\\&password=%s", + attributeWhenReady(mysql, MySqlNode.MYSQL_URL), + DB_TABLE, DB_USERNAME, DB_PASSWORD)); + + web.getCluster().addPolicy(AutoScalerPolicy.builder(). + metric(DynamicWebAppCluster.AVERAGE_REQUESTS_PER_SECOND). + sizeRange(1, 5). + metricRange(10, 100). + build()); + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new WebClusterDatabaseExampleGroovy() + .appDisplayName("Brooklyn WebApp Cluster with Database example") + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } + +} diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.java b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.java new file mode 100644 index 0000000..f0b7b50 --- /dev/null +++ b/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.java @@ -0,0 +1,87 @@ +package brooklyn.demo; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.config.BrooklynProperties; +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.StartableApplication; +import brooklyn.entity.proxy.nginx.NginxController; +import brooklyn.entity.proxying.BasicEntitySpec; +import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import brooklyn.entity.webapp.DynamicWebAppCluster; +import brooklyn.entity.webapp.jboss.JBoss7Server; +import brooklyn.launcher.BrooklynLauncher; +import brooklyn.launcher.BrooklynServerDetails; +import brooklyn.location.Location; +import brooklyn.policy.autoscaling.AutoScalerPolicy; +import brooklyn.util.CommandLineUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +/** + * Launches a clustered and load-balanced set of web servers. + * Demonstrates syntax, so many of the options used here are the defaults. + * (So the class could be much simpler, as in WebClusterExampleAlt.) + *

+ * Requires: + * -Xmx512m -Xms128m -XX:MaxPermSize=256m + * and brooklyn-all jar, and this jar or classes dir, on classpath. + **/ +public class WebClusterExample extends ApplicationBuilder { + public static final Logger LOG = LoggerFactory.getLogger(WebClusterExample.class); + + static BrooklynProperties config = BrooklynProperties.Factory.newDefault(); + + public static final String DEFAULT_LOCATION = "localhost"; + + public static final String WAR_PATH = "classpath://hello-world-webapp.war"; + + private NginxController nginxController; + private ControlledDynamicWebAppCluster web; + + protected void doBuild() { + nginxController = createChild(BasicEntitySpec.newInstance(NginxController.class) + //.configure("domain", "webclusterexample.brooklyn.local") + .configure("port", "8000+")); + + web = createChild(ControlledDynamicWebAppCluster.Spec.newInstance() + .displayName("WebApp cluster") + .controller(nginxController) + .initialSize(1) + .memberSpec(BasicEntitySpec.newInstance(JBoss7Server.class) + .configure("httpPort", "8080+") + .configure("war", WAR_PATH))); + + web.getCluster().addPolicy(AutoScalerPolicy.builder() + .metric(DynamicWebAppCluster.AVERAGE_REQUESTS_PER_SECOND) + .sizeRange(1, 5) + .metricRange(10, 100) + .build()); + } + + public static void main(String[] argv) { + List args = Lists.newArrayList(argv); + String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+"); + String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION); + + BrooklynServerDetails server = BrooklynLauncher.newLauncher() + .webconsolePort(port) + .launch(); + + // TODO Want to parse, to handle multiple locations + Location loc = server.getManagementContext().getLocationRegistry().resolve(location); + + StartableApplication app = new WebClusterExample() + .appDisplayName("Brooklyn WebApp Cluster example") + .manage(server.getManagementContext()); + + app.start(ImmutableList.of(loc)); + + Entities.dumpInfo(app); + } +} diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.groovy b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/SingleWebServerExample.groovy similarity index 87% rename from simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.groovy rename to simple-web-cluster/src/main/java/brooklyn/demo/legacy/SingleWebServerExample.groovy index 776fa2c..872a72a 100644 --- a/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.groovy +++ b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/SingleWebServerExample.groovy @@ -1,12 +1,11 @@ -package brooklyn.demo; - -import java.util.List +package brooklyn.demo.legacy; import org.slf4j.Logger import org.slf4j.LoggerFactory import brooklyn.entity.basic.AbstractApplication import brooklyn.entity.webapp.jboss.JBoss7Server +import brooklyn.entity.webapp.jboss.JBoss7ServerImpl import brooklyn.location.basic.CommandLineLocations import brooklyn.location.basic.LocalhostMachineProvisioningLocation @@ -18,7 +17,7 @@ public class SingleWebServerExample extends AbstractApplication { public static final List DEFAULT_LOCATIONS = [ CommandLineLocations.newLocalhostLocation() ] private static final String WAR_PATH = "classpath://hello-world-webapp.war" - JBoss7Server web = new JBoss7Server(this, war: WAR_PATH, httpPort: 8080) + JBoss7Server web = new JBoss7ServerImpl(this, war: WAR_PATH, httpPort: 8080) public static void main(String[] args) { SingleWebServerExample app = new SingleWebServerExample(); diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.groovy b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExample.groovy similarity index 91% rename from simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.groovy rename to simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExample.groovy index 6d6cac0..ab9092b 100644 --- a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.groovy +++ b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExample.groovy @@ -1,4 +1,4 @@ -package brooklyn.demo +package brooklyn.demo.legacy import static brooklyn.entity.java.JavaEntityMethods.javaSysProp import static brooklyn.entity.webapp.WebAppServiceConstants.HTTP_PORT @@ -12,7 +12,9 @@ import org.slf4j.LoggerFactory import brooklyn.entity.basic.AbstractApplication import brooklyn.entity.basic.Entities import brooklyn.entity.database.mysql.MySqlNode +import brooklyn.entity.database.mysql.MySqlNodeImpl import brooklyn.entity.webapp.ControlledDynamicWebAppCluster +import brooklyn.entity.webapp.ControlledDynamicWebAppClusterImpl import brooklyn.entity.webapp.DynamicWebAppCluster import brooklyn.launcher.BrooklynLauncher import brooklyn.launcher.BrooklynServerDetails @@ -39,8 +41,8 @@ public class WebClusterDatabaseExample extends AbstractApplication { public static final String DB_PASSWORD = "br00k11n" - ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppCluster(this, war: WAR_PATH); - MySqlNode mysql = new MySqlNode(this, creationScriptUrl: DB_SETUP_SQL_URL); + ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppClusterImpl(this, war: WAR_PATH); + MySqlNode mysql = new MySqlNodeImpl(this, creationScriptUrl: DB_SETUP_SQL_URL); { web.configure(HTTP_PORT, "8080+"). diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleAlt.groovy b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExampleAlt.groovy similarity index 88% rename from simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleAlt.groovy rename to simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExampleAlt.groovy index 6e4f371..98cd100 100644 --- a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleAlt.groovy +++ b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExampleAlt.groovy @@ -1,7 +1,4 @@ -package brooklyn.demo - -import java.util.List -import java.util.Map +package brooklyn.demo.legacy import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -11,11 +8,14 @@ import brooklyn.entity.Entity import brooklyn.entity.basic.AbstractApplication import brooklyn.entity.basic.Entities import brooklyn.entity.database.mysql.MySqlNode -import brooklyn.entity.proxy.nginx.NginxController +import brooklyn.entity.database.mysql.MySqlNodeImpl +import brooklyn.entity.proxy.nginx.NginxControllerImpl import brooklyn.entity.webapp.ControlledDynamicWebAppCluster +import brooklyn.entity.webapp.ControlledDynamicWebAppClusterImpl import brooklyn.entity.webapp.DynamicWebAppCluster import brooklyn.entity.webapp.JavaWebAppService import brooklyn.entity.webapp.jboss.JBoss7Server +import brooklyn.entity.webapp.jboss.JBoss7ServerImpl import brooklyn.event.basic.DependentConfiguration import brooklyn.launcher.BrooklynLauncher import brooklyn.location.Location @@ -69,10 +69,10 @@ INSERT INTO MESSAGES values (default, 'Isaac Asimov', 'I grew up in Brooklyn' ); setConfig(JavaWebAppService.ROOT_WAR, WAR_PATH) } - MySqlNode mysql = new MySqlNode(this, creationScriptContents: DB_SETUP_SQL); + MySqlNode mysql = new MySqlNodeImpl(this, creationScriptContents: DB_SETUP_SQL); protected JavaWebAppService newWebServer(Map flags, Entity cluster) { - JBoss7Server jb7 = new JBoss7Server(flags).configure(httpPort: "8000+"); + JBoss7Server jb7 = new JBoss7ServerImpl(flags).configure(httpPort: "8000+"); jb7.setConfig(JBoss7Server.JAVA_SYSPROPS, ["brooklyn.example.db.url": //"jdbc:mysql://localhost/visitors?user=brooklyn&password=br00k11n" DependentConfiguration.valueWhenAttributeReady(mysql, MySqlNode.MYSQL_URL, @@ -81,8 +81,8 @@ INSERT INTO MESSAGES values (default, 'Isaac Asimov', 'I grew up in Brooklyn' ); return jb7; } - ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppCluster(this, - controller: new NginxController(port: 8080), + ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppClusterImpl(this, + controller: new NginxControllerImpl(port: 8080), factory: this.&newWebServer ) AutoScalerPolicy policy = AutoScalerPolicy.builder() diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleAltJava.java b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExampleAltJava.java similarity index 91% rename from simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleAltJava.java rename to simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExampleAltJava.java index 3a0f9ef..e8f9bb8 100644 --- a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleAltJava.java +++ b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterDatabaseExampleAltJava.java @@ -1,4 +1,4 @@ -package brooklyn.demo; +package brooklyn.demo.legacy; import static brooklyn.event.basic.DependentConfiguration.valueWhenAttributeReady; @@ -16,8 +16,11 @@ import brooklyn.config.BrooklynProperties; import brooklyn.entity.basic.AbstractApplication; import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.EntityLocal; import brooklyn.entity.database.mysql.MySqlNode; +import brooklyn.entity.database.mysql.MySqlNodeImpl; import brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import brooklyn.entity.webapp.ControlledDynamicWebAppClusterImpl; import brooklyn.entity.webapp.DynamicWebAppCluster; import brooklyn.entity.webapp.WebAppService; import brooklyn.entity.webapp.jboss.JBoss7Server; @@ -65,11 +68,11 @@ public WebClusterDatabaseExampleAltJava(Map props) { super(props); } - ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppCluster(this); - MySqlNode mysql = new MySqlNode(this); + ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppClusterImpl(this); + MySqlNodeImpl mysql = new MySqlNodeImpl(this); - { - web.setConfig(ControlledDynamicWebAppCluster.ROOT_WAR, WAR_PATH); + { + ((EntityLocal)web).setConfig(ControlledDynamicWebAppCluster.ROOT_WAR, WAR_PATH); mysql.setConfig(MySqlNode.CREATION_SCRIPT_URL, DB_SETUP_SQL_URL); web.getFactory().setConfig(WebAppService.HTTP_PORT, "8080+"); Map jvmSysProps = new LinkedHashMap(); diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.groovy b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterExample.groovy similarity index 91% rename from simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.groovy rename to simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterExample.groovy index 81f0930..ae4aea4 100644 --- a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.groovy +++ b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterExample.groovy @@ -1,7 +1,4 @@ -package brooklyn.demo - -import java.util.List -import java.util.Map +package brooklyn.demo.legacy import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -10,12 +7,13 @@ import brooklyn.config.BrooklynProperties import brooklyn.entity.basic.AbstractApplication import brooklyn.entity.basic.Entities import brooklyn.entity.proxy.nginx.NginxController +import brooklyn.entity.proxy.nginx.NginxControllerImpl import brooklyn.entity.webapp.ControlledDynamicWebAppCluster +import brooklyn.entity.webapp.ControlledDynamicWebAppClusterImpl import brooklyn.entity.webapp.DynamicWebAppCluster import brooklyn.entity.webapp.jboss.JBoss7ServerFactory import brooklyn.launcher.BrooklynLauncher import brooklyn.location.Location -import brooklyn.location.basic.CommandLineLocations import brooklyn.location.basic.LocationRegistry import brooklyn.policy.autoscaling.AutoScalerPolicy import brooklyn.util.CommandLineUtil @@ -43,13 +41,13 @@ public class WebClusterExample extends AbstractApplication { } - NginxController nginxController = new NginxController(this, + NginxController nginxController = new NginxControllerImpl(this, // domain: 'webclusterexample.brooklyn.local', port:"8000+") JBoss7ServerFactory jbossFactory = new JBoss7ServerFactory(httpPort: "8080+", war: WAR_PATH); - ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppCluster(this, + ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppClusterImpl(this, name: "WebApp cluster", controller: nginxController, initialSize: 1, diff --git a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExampleAlt.groovy b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterExampleAlt.groovy similarity index 92% rename from simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExampleAlt.groovy rename to simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterExampleAlt.groovy index 64b087d..4852254 100644 --- a/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExampleAlt.groovy +++ b/simple-web-cluster/src/main/java/brooklyn/demo/legacy/WebClusterExampleAlt.groovy @@ -1,20 +1,17 @@ -package brooklyn.demo +package brooklyn.demo.legacy import groovy.transform.InheritConstructors -import java.util.List -import java.util.Map - import org.slf4j.Logger import org.slf4j.LoggerFactory import brooklyn.entity.basic.AbstractApplication import brooklyn.entity.basic.Entities import brooklyn.entity.webapp.ControlledDynamicWebAppCluster +import brooklyn.entity.webapp.ControlledDynamicWebAppClusterImpl import brooklyn.entity.webapp.DynamicWebAppCluster import brooklyn.launcher.BrooklynLauncher import brooklyn.location.Location -import brooklyn.location.basic.CommandLineLocations import brooklyn.location.basic.LocationRegistry import brooklyn.policy.autoscaling.AutoScalerPolicy import brooklyn.util.CommandLineUtil @@ -35,7 +32,7 @@ public class WebClusterExampleAlt extends AbstractApplication { public static final String WAR_PATH = "classpath://hello-world-webapp.war" - ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppCluster(this, war: WAR_PATH); + ControlledDynamicWebAppCluster web = new ControlledDynamicWebAppClusterImpl(this, war: WAR_PATH); { web.addPolicy(AutoScalerPolicy.builder() .metric(DynamicWebAppCluster.AVERAGE_REQUESTS_PER_SECOND)