Removed cloud foundry module since it is broken
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/4ccaf5a3 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/4ccaf5a3 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/4ccaf5a3 Branch: refs/heads/0.5.0 Commit: 4ccaf5a334cd74341890b786f1a74e6822471b2b Parents: a8f4c0f Author: Peter Veentjer <[email protected]> Authored: Thu Apr 18 16:56:43 2013 +0300 Committer: Peter Veentjer <[email protected]> Committed: Thu Apr 18 16:56:43 2013 +0300 ---------------------------------------------------------------------- pom.xml | 1 - systems/paas/cloudfoundry/pom.xml | 39 -- .../CloudFoundryJavaWebAppCluster.groovy | 193 --------- .../cloudfoundry/CloudFoundryLocation.groovy | 119 ------ .../CloudFoundryVmcCliAccess.groovy | 412 ------------------- .../services/brooklyn.location.LocationResolver | 1 - .../CloudFoundryAccessIntegrationTest.groovy | 82 ---- .../CloudFoundryJavaClusterExample.groovy | 72 ---- ...FoundryJavaClusterFromLocationExample.groovy | 78 ---- .../cloudfoundry/CloudFoundryParseTest.java | 57 --- .../cloudfoundry/LocationResolvesTest.java | 41 -- .../src/test/resources/hello-world.war | Bin 4606 -> 0 bytes 12 files changed, 1095 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 1e6aaa1..6da5302 100644 --- a/pom.xml +++ b/pom.xml @@ -602,7 +602,6 @@ <module>systems/whirr/base</module> <module>systems/whirr/hadoop</module> <module>systems/paas/openshift</module> - <module>systems/paas/cloudfoundry</module> </modules> </profile> <profile> http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/pom.xml ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/pom.xml b/systems/paas/cloudfoundry/pom.xml deleted file mode 100644 index 758c79c..0000000 --- a/systems/paas/cloudfoundry/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <artifactId>brooklyn-systems-cloudfoundry</artifactId> - <packaging>bundle</packaging> - <name>Brooklyn CloudFoundry PaaS System Entities</name> - <description> - Brooklyn entities for CloudFoundry PaaS system (java web app) - </description> - - <parent> - <groupId>io.brooklyn</groupId> - <artifactId>brooklyn-parent</artifactId> - <version>0.5.0-SNAPSHOT</version> <!-- BROOKLYN_VERSION --> - <relativePath>../../../pom.xml</relativePath> - </parent> - - <dependencies> - <dependency> - <groupId>io.brooklyn</groupId> - <artifactId>brooklyn-software-webapp</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>brooklyn-test-support</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.brooklyn</groupId> - <artifactId>brooklyn-core</artifactId> - <version>${project.version}</version> - <classifier>tests</classifier> - <scope>test</scope> - </dependency> - </dependencies> - -</project> http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaWebAppCluster.groovy ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaWebAppCluster.groovy b/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaWebAppCluster.groovy deleted file mode 100644 index 174d5fb..0000000 --- a/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaWebAppCluster.groovy +++ /dev/null @@ -1,193 +0,0 @@ -package brooklyn.extras.cloudfoundry - - -import java.util.Collection -import java.util.Map - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.entity.Entity -import brooklyn.entity.basic.AbstractEntity -import brooklyn.entity.basic.Attributes -import brooklyn.entity.basic.BasicConfigurableEntityFactory -import brooklyn.entity.basic.Lifecycle -import brooklyn.entity.trait.Resizable -import brooklyn.entity.trait.Startable -import brooklyn.entity.webapp.ElasticJavaWebAppService -import brooklyn.event.adapter.FunctionSensorAdapter -import brooklyn.event.adapter.SensorRegistry -import brooklyn.event.basic.BasicAttributeSensor -import brooklyn.event.basic.BasicConfigKey -import brooklyn.extras.cloudfoundry.CloudFoundryVmcCliAccess.AppRecord -import brooklyn.extras.cloudfoundry.CloudFoundryVmcCliAccess.CloudFoundryAppStats -import brooklyn.location.Location -import brooklyn.util.StringUtils; -import brooklyn.util.flags.SetFromFlag -import brooklyn.util.mutex.MutexSupport -import brooklyn.util.mutex.WithMutexes - -import com.google.common.base.Preconditions -import com.google.common.collect.Iterables - -class CloudFoundryJavaWebAppCluster extends AbstractEntity implements ElasticJavaWebAppService, Startable, Resizable { - //Startable shouldn't have to be declared but sometimes it isn't picked up??!?! - - private static final Logger log = LoggerFactory.getLogger(CloudFoundryJavaWebAppCluster.class) - - @SetFromFlag("appName") - public static final BasicConfigKey<String> APP_NAME = [ String, "cloudfoundry.app.name.uid", "Unique name for this app" ]; - @SetFromFlag("url") - public static final BasicConfigKey<String> HOSTNAME_TO_USE_FOR_URL = [ String, "cloudfoundry.app.url", "URL to which the app should respond, if not the default" ]; - - public static final BasicAttributeSensor<String> APP_HOSTNAME = Attributes.HOSTNAME; - public static final BasicAttributeSensor<String> API_HOSTNAME = [ String, "cloudfoundry.api.host.name", "API host name" ]; - - //TODO allow url to be set - //disabled until we have access to a CF which allows setting the URL - //(see refs to getUrl and url in VmcCliAccess) - //(and note, this is different to ROOT_URL which _is_ exposed as a _sensor_) -// @SetFromFlag("url") -// public static final BasicConfigKey<String> URL = [ String, "cloudfoundry.app.url", "URL this app should respond to" ] - - public static final SERVICE_STATE = Attributes.SERVICE_STATE - - public static final BasicAttributeSensor<Integer> SIZE = [ Integer, "cloudfoundry.instances.size", "Number of instances" ]; - public static final BasicAttributeSensor<Double> CPU_USAGE = [ Double, "cloudfoundry.cpu.usage", "Average CPU utilisation (in [0..1], mean over number of instances and CPUs)" ]; - public static final BasicAttributeSensor<Double> MEMORY_USED_FRACTION = [ Double, "cloudfoundry.memory.usage.fraction", "Average memory utilisation (in [0..1])" ]; - - public AppRecord appRecord; - protected transient SensorRegistry sensorRegistry; - - public CloudFoundryJavaWebAppCluster(Map flags=[:], Entity parent=null) { - super(flags, parent); - setAttribute(SERVICE_UP, false) - setAttribute(SERVICE_STATE, Lifecycle.CREATED); - sensorRegistry = new SensorRegistry(this); - } - - public String getAppName() { - def appName = getConfig(APP_NAME); - if (appName) return appName; - return "brooklyn-"+getId(); - } - - public String getWar() { - return getConfig(ROOT_WAR); - } - - public void start(Collection<Location> locations) { - if (getConfig(APP_NAME)!=appName) setConfigEvenIfOwned(APP_NAME, appName); - startInLocation locations - } - - public void startInLocation(Collection<? extends Location> locations) { - Preconditions.checkArgument locations.size() == 1 - Location location = Iterables.getOnlyElement(locations) - startInLocation(location) - } - - public void restart() { - stop() - start() - } - public void stop() { - setAttribute(SERVICE_STATE, Lifecycle.STOPPING); - setAttribute(SERVICE_UP, false); - cfAccess.stopApp(); - setAttribute(SERVICE_STATE, Lifecycle.STOPPED); - } - - protected static WithMutexes cfMutex = new MutexSupport(); - - private transient CloudFoundryVmcCliAccess _cfAccess; - public CloudFoundryVmcCliAccess getCfAccess() { - if (_cfAccess!=null) return _cfAccess; - _cfAccess = new CloudFoundryVmcCliAccess( - appName:getAppName(), war: war, context: this, mutexSupport:cfMutex) - _cfAccess.url = getConfig(HOSTNAME_TO_USE_FOR_URL); - return _cfAccess; - } - - public void startInLocation(CloudFoundryLocation ol) { - if (locations.isEmpty()) { - locations << ol - } else { - if (locations.contains(ol)) { - if (getAttribute(SERVICE_STATE) in [Lifecycle.STARTING, Lifecycle.RUNNING]) { - log.warn("Entity $this already started; not starting again in same location"); - return; - } - //otherwise continue, we're just being told the location twice! - } else { - throw new IllegalStateException("Cannot start $this in $ol; it is already configured for $locations"); - } - } - setAttribute(SERVICE_STATE, Lifecycle.STARTING); - - if (!war) throw new IllegalStateException("A WAR file is required to start ${this}") - - useTarget(ol.getTarget()); - appRecord = cfAccess.runAppWar(); - log.info "{} app launched: {}", this, getAppName() - - //add support for DynamicWebAppCluster.startInLocation(CloudFoundry) - connectSensors(); - setAttribute(SERVICE_STATE, Lifecycle.RUNNING); - setAttribute(SERVICE_UP, true) - } - - protected void useTarget(String target) { - if (!target) return; - cfAccess.setTarget(target) - } - - public void connectSensors() { - String apiHostname = ((CloudFoundryLocation)Iterables.getOnlyElement(locations)).hostname; - setAttribute(API_HOSTNAME, apiHostname); - - String appHostname = StringUtils.removeStart(apiHostname, "api."); - appHostname = appRecord.appName+"."+appHostname; - setAttribute(APP_HOSTNAME, appHostname); - - String urlDomain = appRecord.url; - setAttribute(ROOT_URL, "http://"+urlDomain+"/"); - - sensorRegistry.register(new FunctionSensorAdapter({cfAccess.stats()})).with { - poll(SIZE, { CloudFoundryAppStats stats -> stats.instances.size() }); - poll(CPU_USAGE, { CloudFoundryAppStats stats -> stats.average.cpuUsage }); - poll(MEMORY_USED_FRACTION, { CloudFoundryAppStats stats -> stats.average.memUsedFraction }); - } - } - - public String getWebAppAddress() { - return cfAccess.getUrl(); - } - - public void destroy() { - log.info "{} destroying app {}", this, getAppName() - setAttribute(SERVICE_UP, false) - setAttribute(SERVICE_STATE, Lifecycle.STOPPING); - sensorRegistry.deactivateAdapters(); - if (cfAccess.getAppRecord(getAppName(), true)) - cfAccess.destroyApp(); - setAttribute(SERVICE_STATE, Lifecycle.STOPPED); - } - - @Override - public Integer resize(Integer desiredSize) { - cfAccess.resizeAbsolute(desiredSize); - //could block until SIZE sensor report achieved, or timeout; - //but it seems the command-line call is synchronous so not necessary - } - - @Override - public Integer getCurrentSize() { - return getAttribute(SIZE); - } - - - public static class Factory extends BasicConfigurableEntityFactory<CloudFoundryJavaWebAppCluster> { - public Factory(Map flags=[:]) { super(flags, CloudFoundryJavaWebAppCluster) } - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryLocation.groovy ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryLocation.groovy b/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryLocation.groovy deleted file mode 100644 index 5027856..0000000 --- a/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryLocation.groovy +++ /dev/null @@ -1,119 +0,0 @@ -package brooklyn.extras.cloudfoundry - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.entity.basic.ConfigurableEntityFactory -import brooklyn.entity.webapp.ElasticJavaWebAppService -import brooklyn.entity.webapp.ElasticJavaWebAppService.ElasticJavaWebAppServiceAwareLocation -import brooklyn.location.AddressableLocation -import brooklyn.location.Location -import brooklyn.location.LocationResolver -import brooklyn.location.basic.AbstractLocation -import brooklyn.location.geo.HostGeoInfo -import brooklyn.util.NetworkUtils -import brooklyn.util.StringUtils -import brooklyn.util.flags.SetFromFlag -import brooklyn.util.mutex.MutexSupport -import brooklyn.util.mutex.WithMutexes - - -/** defines a cloudfoundry location - * <p> - * this can be specified as 'cloudfoundry:api.cloudfoundry.com', - * or as 'cloudfoundry:https://api.aws.af.cm/' (required by `vmc` if target requires https) - * or just 'cloudfoundry' (to use the default `vmc target`, in ~/.vmc_target) - * <p> - * username+password are not currently specifiable; - * we assume a token has been set up via `vmc login` (stored in ~/.vmc_token) */ -class CloudFoundryLocation extends AbstractLocation implements AddressableLocation, ElasticJavaWebAppServiceAwareLocation, WithMutexes { - - public static final Logger log = LoggerFactory.getLogger(CloudFoundryLocation.class); - - @SetFromFlag - private String target; - - public CloudFoundryLocation(Map properties = [:]) { - super(properties); - if (!target) target="api.cloudfoundry.com"; - if (!name) name="Cloud Foundry @ "+target; - if (getHostGeoInfo()==null) setHostGeoInfo(HostGeoInfo.fromLocation(this)); - } - - public static class Resolver implements LocationResolver { - @Override - public String getPrefix() { - return "cloudfoundry"; - } - - @Override - public Location newLocationFromString(Map properties, String spec) { - if (spec.equals(getPrefix())) - return new CloudFoundryLocation(); - String target = spec.substring(spec.indexOf(':')+1); - // target endpoint is allowed to be specified here as second part of spec - // default of null means to use whatever vmc is configured with - return new CloudFoundryLocation(target: target); - } - } - - @Override - public ConfigurableEntityFactory<ElasticJavaWebAppService> newWebClusterFactory() { - return new CloudFoundryJavaWebAppCluster.Factory(); - } - - public String getTarget() { - return this.@target; - } - - public String getHostname() { - if (!target) return null; - String hostname = target; - use (StringUtils) { - hostname = hostname. - removeStart("http://"). - removeStart("https://"). - replaceAll("/.*\$", ""); - } - return hostname; - } - - @Override - public InetAddress getAddress() { - if (!target) return null; - if (hostname?.isEmpty()) - throw new IllegalArgumentException("Cannot parse Cloud Foundry target '"+target+"' to determine address; expected in api.hostname.com or https://api.hostname.com/xxx format.") - try { - return NetworkUtils.getInetAddressWithFixedName(hostname); - } catch (Exception e) { - if (log.isDebugEnabled()) - log.warn("unable to look up IP info for "+hostname+": "+e); - return null; - } - } - - // make this a static because it has to be shared across all instances on a machine - // (using the command-line tool vmc) - static WithMutexes mutexSupport = new MutexSupport(); - - @Override - public void acquireMutex(String mutexId, String description) throws InterruptedException { - mutexSupport.acquireMutex(mutexId, description); - } - - @Override - public boolean tryAcquireMutex(String mutexId, String description) { - return mutexSupport.tryAcquireMutex(mutexId, description); - } - - @Override - public void releaseMutex(String mutexId) { - mutexSupport.releaseMutex(mutexId); - } - - @Override - public boolean hasMutex(String mutexId) { - return mutexSupport.hasMutex(mutexId); - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryVmcCliAccess.groovy ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryVmcCliAccess.groovy b/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryVmcCliAccess.groovy deleted file mode 100644 index 673fc2c..0000000 --- a/systems/paas/cloudfoundry/src/main/java/brooklyn/extras/cloudfoundry/CloudFoundryVmcCliAccess.groovy +++ /dev/null @@ -1,412 +0,0 @@ -package brooklyn.extras.cloudfoundry - -import groovy.transform.EqualsAndHashCode - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.entity.Entity -import brooklyn.util.ResourceUtils -import brooklyn.util.ShellUtils -import brooklyn.util.mutex.WithMutexes -import brooklyn.util.text.Identifiers; - -class CloudFoundryVmcCliAccess { - - private static final Logger log = LoggerFactory.getLogger(CloudFoundryVmcCliAccess.class) - - /** optional user-supplied context object used for classloading context and - * inserting into toString to help with context */ - protected Object context = this; - - String appName, war, url, target; - WithMutexes mutexSupport; - - String appPath; - public synchronized String getAppPath() { - if (this.@appPath) return this.@appPath; - if (context in Entity) { - appPath = "/tmp/brooklyn/apps/"+((Entity)context).application.id+"/staging/"+ - "cloudfoundry/"+((Entity)context).id+"/"; - } else { - appPath = "/tmp/brooklyn/cloudfoundry/"+Identifiers.makeRandomId(6)+"/" - } - return this.@appPath - } - - protected def requiredFields = []; - // { requiredFields += ["target", "username", "password"] } - - protected validate() { - requiredFields.each { - if (this."${it}"==null) throw new NullPointerException("Flag '${it}' must be passed to constructor for "+this.getClass().getSimpleName()); - } - } - - public String toString() { - if (context==this || context==null) return "brooklyn:"+getClass().getSimpleName(); - return "CfVmc:"+context; - } - - /** returns lines of the form PATH=/usr/bin:/usr/local/bin:. - * for use passing to exec */ - protected static String[] getDefaultEnvironmentForExec() { - System.getenv().collect { k,v -> "${k}=${v}" } - } - - protected String[] exec(String cmd) { - // 10min timeout - ShellUtils.exec(timeout: 10*60*1000, cmd, log, context); - } - protected String[] exec(String cmd, String input) { - ShellUtils.exec(timeout: 10*60*1000, cmd, input, log, context); - } - - private Map<String,AppRecord> apps = null; - public synchronized Map<String,AppRecord> getApps(boolean refresh=false) { - if (refresh || apps==null) apps=_apps(); - return apps; - } - public AppRecord getAppRecord(String appName, boolean refresh=false) { - getApps(refresh).get(appName); - } - public Collection<String> getAppNames(boolean refresh=false) { - getApps(refresh).keySet(); - } - @EqualsAndHashCode - public static class AppRecord implements Serializable { - String appName, state, url; - int size; - List services = [] - public static AppRecord parse(String line) { - def fields = line.split("\\|"); - AppRecord result = new AppRecord( - appName: fields[1].trim(), - size: Integer.parseInt(fields[2].trim()), - state: fields[3].trim(), - url: fields[4].trim()) - for (String svc : fields[5].trim().split("\\s+")) { - //add services (skip blank entries introduced by split) - if (svc) result.services << svc - } - return result - } - } - protected Map<String,AppRecord> _apps() { - validate(); - Map result = [:] - useTarget(target, "lookup apps") { - String[] lines = exec("vmc apps"); - // +---------------+----+---------+--------------------------------+-------------+ - // | Application | # | Health | URLS | Services | - // +---------------+----+---------+--------------------------------+-------------+ - // | hellobrooklyn | 1 | RUNNING | hellobrooklyn.cloudfoundry.com | mysql-8c1d0 | - // | hellobrookly2 | 1 | RUNNING | hellobrookly2.cloudfoundry.com | mysql-8c1d0 | - // +---------------+----+---------+--------------------------------+-------------+ - - def li = lines.iterator(); - //skip 3 header lines; bail out if not enough (e.g. 'No Applications') - if (!li.hasNext()) return result; else li.next(); - if (!li.hasNext()) return result; else li.next(); - if (!li.hasNext()) return result; else li.next(); - while (li.hasNext()) { - String line = li.next(); - if (line.startsWith("+---")) - continue; - def record = AppRecord.parse(line); - result.put(record.appName, record); - } - } - - result - } - - public String getAppName(Map localFlags) { - String appName = localFlags.appName ?: this.@appName; - if (appName) return appName; - throw new NullPointerException("appName is required for ${context}"); - } - - public String getWar(Map localFlags) { - String war = localFlags.war ?: this.@war; - if (war) return war; - throw new NullPointerException("war is required for this operation on ${context}"); - } - - public String getUrl(Map localFlags=[:]) { - //not permitted on cloudfoundry.com; might work elsewhere - String url = localFlags.url ?: this.@url; - if (url) return url; - return getAppRecord(getAppName(localFlags))?.url - } - - /** sets the target location that will be used, e.g. api.cloudfoundry.com - * <p> - * we assume vmc on the local system has already been configured to log in to that endpoint, - * so user+pass is not used. by default the last target set will be used. - * <p> - * this is not parallel-safe (if someone else switches target); - * we compensate for that by always calling setTarget(target), - * which is not safe by itself but if wrapped in a useTarget block - * is safe unless something outside brooklyn retargets vmc at the same time. - * (a cleaner alternative would be to use a java API as described in issue #15.) - */ - public void setTarget(String target) { - this.target = target; - setTarget(); - } - protected void setTarget() { - if (target) exec("vmc target ${target}") - } - - public Object useTarget(String target, String description, Closure code) { - boolean hasMutex = false; - try { - if (mutexSupport && !mutexSupport.hasMutex("vmc")) { - if (log.isDebugEnabled()) log.debug("acquiring vmc mutex for $target $description") - mutexSupport.acquireMutex("vmc", "Cloud Foundry vmc target ${target} - "+description); - if (log.isDebugEnabled()) log.debug("acquired vmc mutex for $target") - hasMutex = true; - } - setTarget(); - return code.call(); - } finally { - if (hasMutex) { - if (log.isDebugEnabled()) log.debug("releasing vmc mutex for $target") - mutexSupport.releaseMutex("vmc"); - } - } - } - - public String getTarget() { target } - - /** flags appName and war (URL of deployable resource) required; - * memory (eg "512M") and url (target url) optional - */ - public AppRecord runAppWar(Map flags=[:]) { - Collection apps = getAppNames(); - - String appName = getAppName(flags); - String appPath = getAppPath(); - new File(appPath).mkdirs(); - new File(appPath+"/root.war") << new ResourceUtils(context).getResourceFromUrl(getWar(flags)); - - useTarget(target, "run ${appName} WAR") { - if (apps.contains(appName)) { - //update - - //stop done implicitly on server - // exec("vmc stop ${appName}") - - if (flags.memory) exec("vmc mem ${appName} "+flags.memory); - if (flags.url) { - url = getUrl(flags) - exec("vmc map ${appName} "+url); - } - - exec("vmc update ${appName} --path ${appPath}"); - - exec("vmc start ${appName}") - } else { - //create - String memory = flags.memory ?: "512M"; - url = getUrl(flags) - exec("vmc push"+ - " ${appName}"+ - (url ? " --url ${url}" : "")+ - " --path ${appPath}"+ - //" --runtime java"+ //what is syntax here? vmc runtimes shows java; frameworks shows java_web; all seem to prompt - " --mem 512M", - //need CR supplied twice (java prompt, and services prompt) since can't seem to get it specified on CLI; - //and once more if url is default - "\n\n"+(url?"":"\n")); - } - - AppRecord result = this.getAppRecord(appName, true); - if (result==null) - throw new IllegalStateException("Failed to start $this"); - url = result.url - return result - } - } - - public void stopApp(Map flags=[:]) { - useTarget(target, "delete ${getAppName(flags)}") { - exec("vmc stop ${getAppName(flags)}"); - } - } - - public void destroyApp(Map flags=[:]) { - useTarget(target, "delete ${getAppName(flags)}") { - exec("vmc delete ${getAppName(flags)}"); - } - } - - public void resizeAbsolute(Map flags=[:], int newSize) { - if (newSize<0) throw new IllegalArgumentException("newSize cannot be negative for ${context}") - useTarget(target, "resize ${getAppName(flags)} to ${newSize}") { - exec("vmc instances ${getAppName(flags)} "+newSize); - } - } - public void resizeDelta(Map flags=[:], int delta) { - useTarget(target, "resize ${getAppName(flags)} ${(delta>=0?"+"+delta:delta)}") { - exec("vmc instances ${getAppName(flags)} "+(delta>=0?"+"+delta:delta)); - } - } - - public static class CloudFoundryAppStats { - List<CloudFoundryAppStatLine> instances; - CloudFoundryAppStatLine average; - public int getSize() { instances.size() } - @Override - public String toString() { - return "CloudFoundryAppStats[size="+size+";average="+average+"]"; - } - } - public static class CloudFoundryAppStatLine { - double cpuUsage; - int numCores; - double memUsedMB; - double memLimitMB; - double memUsedFraction; - - double diskUsedMB; - double diskLimitMB; - double diskUsedFraction; - - long uptimeSeconds; - - @Override - public String toString() { - return "CloudFoundryStats["+ - "cpu="+cpuUsage+","+ - "cores="+numCores+","+ - "mem="+memUsedMB+"/"+memLimitMB+","+ - "disk="+diskUsedMB+"/"+diskLimitMB+","+ - "uptime="+uptimeSeconds+"]"; - } - - public static CloudFoundryAppStatLine parse(String l) { - // | 0 | 0.0% (4) | 116.6M (512M) | 9.5M (2G) | 0d:15h:41m:2s | - String[] fields = l.split("\\s+"); - CloudFoundryAppStatLine result = new CloudFoundryAppStatLine(); - int i=3; - result.cpuUsage = parseDouble(fields[i++]) / 100; - result.numCores = parseInt(fields[i++]); - i++ - result.memUsedMB = parseSizeMB(fields[i++]); - result.memLimitMB = parseSizeMB(fields[i++]); - result.memUsedFraction = result.memUsedMB/result.memLimitMB; - i++ - result.diskUsedMB = parseSizeMB(fields[i++]); - result.diskLimitMB = parseSizeMB(fields[i++]); - result.diskUsedFraction = result.diskUsedMB/result.diskLimitMB; - i++ - result.uptimeSeconds = parseTime(fields[i]); - result - } - - public static double parseDouble(String word) { - if (word==null || word.length()==0) { - log.warn("empty word found in stats, using 0") - return 0; - } - if (word.startsWith("(")) word = word.substring(1); - if (word.endsWith(")")) word = word.substring(0, word.length()-1); - if (word.endsWith("%")) word = word.substring(0, word.length()-1); - if (word.equals("NA")) return 0; //returned early in lifecycle - return Double.parseDouble(word); - } - public static int parseInt(String word) { - if (word==null || word.length()==0) { - log.warn("empty word found in stats, using 0") - return 0; - } - if (word.startsWith("(")) word = word.substring(1); - if (word.endsWith(")")) word = word.substring(0, word.length()-1); - if (word.endsWith("%")) word = word.substring(0, word.length()-1); - if (word.equals("NA")) return 0; //returned early in lifecycle - return Integer.parseInt(word); - } - public static double parseSizeMB(String word) { - if (word.startsWith("(")) word = word.substring(1, word.length()-1); - if ("NA".equals(word)) return 0; - double d = parseDouble(word.substring(0, word.length()-1)); - char c = word.charAt(word.length()-1) - if (c=='M') return d; - if (c=='G') return d*1024; - if (c=='K') return d/1024.0; - if (c=='B') return d/1024.0/1024.0; - //perhaps one day: :) - if (c=='T') return d*1024*1024; - if (c=='P') return d*1024*1024*1024; - throw new IllegalArgumentException("Unparseable size $word"); - } - public static long parseTime(String word) { - if ("NA".equals(word)) return 0; - int split = word.indexOf(':'); - String w = (split>=0 ? word.substring(0, split) : word); - long t = parseInt(w.substring(0, w.length()-1)); - char c = w.charAt(w.length()-1); - switch (c) { - case 'd': t*=24; - case 'h': t*=60; - case 'm': t*=60; - case 's': break; - default: throw new IllegalArgumentException("Unparseable time $w"); - } - if (split>=0) return t + parseTime(word.substring(split+1)); - else return t; - } - - public static CloudFoundryAppStatLine average(Collection<CloudFoundryAppStatLine> stats) { - CloudFoundryAppStatLine result = new CloudFoundryAppStatLine(); - for (CloudFoundryAppStatLine s: stats) { - result.cpuUsage += s.cpuUsage; - result.numCores += s.numCores; - result.memUsedMB += s.memUsedMB; - result.memLimitMB += s.memLimitMB; - result.diskUsedMB += s.diskUsedMB; - result.diskLimitMB += s.diskLimitMB; - result.uptimeSeconds += s.uptimeSeconds; - } - int count = stats.size(); - if (count>0) { - result.cpuUsage /= count; - result.numCores /= count; - result.memUsedMB /= count; - result.memLimitMB /= count; - result.diskUsedMB /= count; - result.diskLimitMB /= count; - result.uptimeSeconds /= count; - } - result.memUsedFraction = result.memUsedMB/result.memLimitMB; - result.diskUsedFraction = result.diskUsedMB/result.diskLimitMB; - result - } - } - - public CloudFoundryAppStats stats(Map flags=[:]) { - useTarget(target, "stats ${getAppName(flags)}") { - String[] lines = exec("vmc stats ${getAppName(flags)}"); - //+----------+-------------+----------------+--------------+---------------+ - //| Instance | CPU (Cores) | Memory (limit) | Disk (limit) | Uptime | - //+----------+-------------+----------------+--------------+---------------+ - //| 0 | 0.0% (4) | 116.6M (512M) | 9.5M (2G) | 0d:15h:41m:2s | - //| 1 | 0.0% (4) | 75.7M (512M) | 9.4M (2G) | 0d:9h:54m:44s | - //+----------+-------------+----------------+--------------+---------------+ - List result = [] - - def li = lines.iterator(); - 3.times { if (li.hasNext()) li.next(); } //skip 3 header lines - while (li.hasNext()) { - String line = li.next(); - if (line.startsWith("+---")) - continue; - result << CloudFoundryAppStatLine.parse(line) - } - return new CloudFoundryAppStats(instances: result, average: CloudFoundryAppStatLine.average(result)); - } - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/main/resources/META-INF/services/brooklyn.location.LocationResolver ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/main/resources/META-INF/services/brooklyn.location.LocationResolver b/systems/paas/cloudfoundry/src/main/resources/META-INF/services/brooklyn.location.LocationResolver deleted file mode 100644 index 50c88dc..0000000 --- a/systems/paas/cloudfoundry/src/main/resources/META-INF/services/brooklyn.location.LocationResolver +++ /dev/null @@ -1 +0,0 @@ -brooklyn.extras.cloudfoundry.CloudFoundryLocation$Resolver http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryAccessIntegrationTest.groovy ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryAccessIntegrationTest.groovy b/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryAccessIntegrationTest.groovy deleted file mode 100644 index 28d752a..0000000 --- a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryAccessIntegrationTest.groovy +++ /dev/null @@ -1,82 +0,0 @@ -package brooklyn.extras.cloudfoundry - -import static brooklyn.test.TestUtils.* -import static org.testng.Assert.* - -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.testng.Assert -import org.testng.annotations.Test - -import com.google.common.collect.Sets; - -import brooklyn.extras.cloudfoundry.CloudFoundryVmcCliAccess.AppRecord -import brooklyn.extras.cloudfoundry.CloudFoundryVmcCliAccess.CloudFoundryAppStatLine -import brooklyn.extras.cloudfoundry.CloudFoundryVmcCliAccess.CloudFoundryAppStats -import brooklyn.util.text.Identifiers; - - -/** requires vmc installed and configured */ -class CloudFoundryAccessIntegrationTest { - - static final Logger log = LoggerFactory.getLogger(CloudFoundryAccessIntegrationTest.class) - - @Test(groups = [ "Integration", "WIP" ]) - public void testVmcInfo() { - List lines = new CloudFoundryVmcCliAccess().exec("vmc info") as List; - String user = lines.find({ it.startsWith("User:") }) - String version = lines.find({ it.startsWith("Client:") }) - Assert.assertNotNull(user, "expected User: in output"); - user = user.substring(5).trim(); - version = version.substring(7).trim() - log.info("vmc user is "+user+" and version is "+version); - Assert.assertTrue(user.indexOf('@')>0); - } - - @Test(groups = [ "Integration", "WIP" ]) - public void testVmcAppsList() { - Collection apps = new CloudFoundryVmcCliAccess().appNames; - log.info("vmc apps gives: "+apps) - //don't know anything is present, just assert no error - } - - @Test(groups = [ "Integration", "WIP" ]) - public void testVmcAppCreateRunUpdateScaleStats() { - String id = "brooklyn-"+Identifiers.makeRandomId(8).toLowerCase(); - CloudFoundryVmcCliAccess access = new CloudFoundryVmcCliAccess(appName: id); - log.info("creating $id in ${access.appPath}"); - Collection apps1 = access.getAppNames(true); - try { - //create - AppRecord record = access.runAppWar(war: "classpath://hello-world.war"); - Collection apps2 = Sets.difference(access.getAppNames(true), apps1); - assertEquals(apps2, [ id ]) - //check record - assertEquals(record.size, 1) - assertTrue(record.url.startsWith(id+"."), "url ${record.url} should start with ${id}.") - assertEquals(record.state, "RUNNING") - assertEquals(record.services, []) - AppRecord r2 = access.getAppRecord(id); - assertEquals(record, r2); - //update - access.runAppWar(war: "classpath://hello-world.war"); - CloudFoundryAppStats stats = access.stats(); - assertEquals(stats.size, 1) - //scale - access.resizeDelta(1); - stats = access.stats(); - log.info("stats $stats") - assertEquals(stats.size, 2) -// //set url -- gives 702 not enabled -// AppRecord r3 = access.runAppWar(war: "classpath://hello-world.war", url: "foo.bar.com"); -// assertEquals(r3, "foo.bar.com"); - } finally { - log.info("destroying $id") - access.destroyApp(); - } - Collection apps3 = access.getAppNames(true); - log.info("apps now $apps3") - assertEquals(apps3, apps1) - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterExample.groovy ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterExample.groovy b/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterExample.groovy deleted file mode 100644 index 89db1bd..0000000 --- a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterExample.groovy +++ /dev/null @@ -1,72 +0,0 @@ -package brooklyn.extras.cloudfoundry - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.catalog.Catalog -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.Entities -import brooklyn.location.basic.LocationRegistry - -/** - * example app showing how to start an cloudfoundry java war - * - * if this doesn't start, we may have too many apps, delete some using: - * <pre> - * {@code - * vmc apps - * vmc delete brooklyn-1234 - * } - * </pre> - * (or online at the cloudfoundry portal) - * or - * <pre> - * {@code - * for x in `vmc apps | grep brooklyn | awk '{ print $2 }'` ; do vmc delete $x ; done - * } - * </pre> - * @author alex - * - */ -public class CloudFoundryJavaClusterExample extends AbstractApplication { - - private static final Logger log = LoggerFactory.getLogger(CloudFoundryJavaClusterExample.class) - - public static final String WAR_FILE_URL = "classpath://hello-world.war"; - - CloudFoundryJavaWebAppCluster cloudfoundry; - - @Override - public void init() { - cloudfoundry = new CloudFoundryJavaWebAppCluster(this, war: WAR_FILE_URL); - } - - // TODO a richer example which starts CloudFoundry alongside Tomcats in EC2 with geoscaling - - // ---- the code above is your app descriptor; code below runs it ---- - - public static void main(String[] args) { - def app = new CloudFoundryJavaClusterExample(); - def locations = new LocationRegistry().resolve([ - "cloudfoundry" -// "cloudfoundry:https://api.your-stackato.example.com/" - ]); - - app.start(locations); - - log.info "should now be able to visit site (for 2m): {}", app.cloudfoundry.getWebAppAddress() - //should now be able to visit (assert?) - - for (int i=0; i<2*6; i++) { - //periodically print stats - Entities.dumpInfo(app.cloudfoundry); - Thread.sleep(10*1000); - } - - //and kill - log.info "now cleaning up that app: {}", app.cloudfoundry.getWebAppAddress() - app.stop() - - log.info "finished, should terminate shortly" - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterFromLocationExample.groovy ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterFromLocationExample.groovy b/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterFromLocationExample.groovy deleted file mode 100644 index 4f21441..0000000 --- a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryJavaClusterFromLocationExample.groovy +++ /dev/null @@ -1,78 +0,0 @@ -package brooklyn.extras.cloudfoundry - -import java.util.Collection - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import brooklyn.entity.basic.AbstractApplication -import brooklyn.entity.basic.Entities -import brooklyn.entity.webapp.ElasticJavaWebAppService -import brooklyn.location.Location - -import com.google.common.collect.Iterables - -/** - * example app showing how to start an cloudfoundry java war - * - * if this doesn't start, we may have too many apps, delete some using: - * <pre> - * {@code - * vmc apps - * vmc delete brooklyn-1234 - * } - * </pre> - * (or online at the cloudfoundry portal) - * or - * <pre> - * {@code - * for x in `vmc apps | grep brooklyn | awk '{ print $2 }'` ; do vmc delete $x ; done - * } - * </pre> - * @author alex - * - */ -class CloudFoundryJavaClusterFromLocationExample extends AbstractApplication { - - private static final Logger log = LoggerFactory.getLogger(CloudFoundryJavaClusterFromLocationExample.class) - - public static final String WAR_FILE_URL = "classpath://hello-world.war"; - - ElasticJavaWebAppService svc; - - @Override - public void init() { - // no-op; see preStart - } - - @Override - public void preStart(Collection<? extends Location> locations) { - svc = new ElasticJavaWebAppService.Factory().newFactoryForLocation( Iterables.getOnlyElement(locations) ). - newEntity(this, war: WAR_FILE_URL); - } - - // the code above is your app descriptor; note, no mention of cloudfoundry - // code below runs it - - - public static void main(String[] args) { - def app = new CloudFoundryJavaClusterFromLocationExample(); - - app.start([new CloudFoundryLocation(target: 'api.cloudfoundry.com')]); - - log.info "should now be able to visit site (for 2m): {}", app.svc.getAttribute(ElasticJavaWebAppService.ROOT_URL) - //should now be able to visit (assert?) - - for (int i=0; i<2*6; i++) { - //periodically print stats - Entities.dumpInfo(app); - Thread.sleep(10*1000); - } - - //and kill - log.info "now cleaning up that app: {}", app - app.stop() - - log.info "finished, should terminate shortly" - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryParseTest.java ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryParseTest.java b/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryParseTest.java deleted file mode 100644 index 6738b0d..0000000 --- a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/CloudFoundryParseTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package brooklyn.extras.cloudfoundry; - -import java.util.Arrays; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.Test; - -import brooklyn.extras.cloudfoundry.CloudFoundryVmcCliAccess.CloudFoundryAppStatLine; -import brooklyn.extras.cloudfoundry.CloudFoundryVmcCliAccess.CloudFoundryAppStats; - -public class CloudFoundryParseTest { - - public static final Logger log = LoggerFactory.getLogger(CloudFoundryParseTest.class); - - @Test - public void testParseStatsLine() { - CloudFoundryAppStatLine stats = CloudFoundryAppStatLine.parse( - "| 0 | 0.0% (4) | 116.6M (512M) | 9.5M (2G) | 0d:15h:41m:2s |"); - log.info("stats: "+stats); - Assert.assertEquals(stats.getCpuUsage(), 0d); - Assert.assertEquals(stats.getNumCores(), 4); - Assert.assertEquals(stats.getMemUsedMB(), 116.6d, 0.0000001); - Assert.assertEquals(stats.getMemLimitMB(), 512d, 0.0000001); - Assert.assertEquals(stats.getMemUsedFraction(), 116.6d/512d, 0.0000001); - Assert.assertEquals(stats.getDiskUsedMB(), 9.5d, 0.0000001); - Assert.assertEquals(stats.getDiskLimitMB(), 2048d, 0.0000001); - Assert.assertEquals(stats.getDiskUsedFraction(), 9.5d/2048d, 0.0000001); - Assert.assertEquals(stats.getUptimeSeconds(), 60*(60*15+41)+2); - } - - @Test - public void testParseStatsAverage() { - CloudFoundryAppStatLine stats1 = CloudFoundryAppStatLine.parse( - "| 0 | 0.0% (4) | 116.6M (512M) | 9.5M (2G) | 0d:15h:41m:2s |"); - CloudFoundryAppStatLine stats2 = CloudFoundryAppStatLine.parse( - "| 0 | 10.0% (4) | 316.6M (512M) | 29.5M (2G) | 0d:13h:41m:2s |"); - - CloudFoundryAppStats stats = new CloudFoundryAppStats(); - stats.setInstances( Arrays.asList(stats1, stats2)); - stats.setAverage(CloudFoundryAppStatLine.average(stats.getInstances())); - - CloudFoundryAppStatLine avg = stats.getAverage(); - - Assert.assertEquals(avg.getCpuUsage(), 0.05d); - Assert.assertEquals(avg.getNumCores(), 4); - Assert.assertEquals(avg.getMemUsedMB(), 216.6d, 0.0000001); - Assert.assertEquals(avg.getMemLimitMB(), 512d, 0.0000001); - Assert.assertEquals(avg.getMemUsedFraction(), 216.6d/512d, 0.0000001); - Assert.assertEquals(avg.getDiskUsedMB(), 19.5d, 0.0000001); - Assert.assertEquals(avg.getDiskLimitMB(), 2048d, 0.0000001); - Assert.assertEquals(avg.getDiskUsedFraction(), 19.5d/2048d, 0.0000001); - Assert.assertEquals(avg.getUptimeSeconds(), 60*(60*14+41)+2); - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/LocationResolvesTest.java ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/LocationResolvesTest.java b/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/LocationResolvesTest.java deleted file mode 100644 index 6239ab4..0000000 --- a/systems/paas/cloudfoundry/src/test/java/brooklyn/extras/cloudfoundry/LocationResolvesTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package brooklyn.extras.cloudfoundry; - -import java.net.InetAddress; - -import brooklyn.config.BrooklynProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import brooklyn.location.AddressableLocation; -import brooklyn.location.basic.LocationRegistry; - -public class LocationResolvesTest { - - public static final Logger log = LoggerFactory.getLogger(LocationResolvesTest.class); - - BrooklynProperties properties; - - @BeforeMethod - public void setUp(){ - properties= BrooklynProperties.Factory.newDefault(); - } - - @Test - public void testCloudFoundryLocationResolves() { - //NB: if this test fails, make sure src/main/resources is on the classpath - //and META-INF/services/brooklyn.location.LocationResolver isn't being clobbered in a poorly shaded jar - Assert.assertNotNull(new LocationRegistry(properties).resolve("cloudfoundry")); - } - - @Test(groups="Integration") - public void testLocationAddress() { - log.info("lookup CF address"); - InetAddress address = ((AddressableLocation)new LocationRegistry(properties).resolve("cloudfoundry")).getAddress(); - log.info("done lookup of CF address, got "+address); - Assert.assertEquals("api.cloudfoundry.com", address.getHostName()); - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4ccaf5a3/systems/paas/cloudfoundry/src/test/resources/hello-world.war ---------------------------------------------------------------------- diff --git a/systems/paas/cloudfoundry/src/test/resources/hello-world.war b/systems/paas/cloudfoundry/src/test/resources/hello-world.war deleted file mode 100644 index 0a127e6..0000000 Binary files a/systems/paas/cloudfoundry/src/test/resources/hello-world.war and /dev/null differ
