You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/14 05:42:46 UTC
[17/54] incubator-brooklyn git commit: [BROOKLYN-162] Renaming
package brooklyn.location
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/AbstractPortableTemplateBuilder.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/AbstractPortableTemplateBuilder.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/AbstractPortableTemplateBuilder.java
deleted file mode 100644
index e5696c2..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/AbstractPortableTemplateBuilder.java
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.templates;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.jclouds.compute.domain.Hardware;
-import org.jclouds.compute.domain.Image;
-import org.jclouds.compute.domain.OsFamily;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.compute.domain.TemplateBuilder;
-import org.jclouds.compute.options.TemplateOptions;
-
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-
-public abstract class AbstractPortableTemplateBuilder<T extends AbstractPortableTemplateBuilder<?>> implements TemplateBuilder {
-
- /** list of commands supplied by user, excluding options */
- protected List<Function<TemplateBuilder,TemplateBuilder>> commands = new ArrayList<Function<TemplateBuilder,TemplateBuilder>>();
-
- private Hardware hardware;
- private Image image;
- private Template template;
- private String locationId;
- private String imageId;
- private String hardwareId;
- private OsFamily os;
- private String osNameRegex;
- private String osDescriptionRegex;
- private String osVersionRegex;
- private String osArchitectureRegex;
- private String hypervisorRegex;
- private Boolean is64bit;
- private String imageNameRegex;
- private String imageDescriptionRegex;
- private String imageVersionRegex;
- private Double minCores;
- private Integer minRam;
- private Double minDisk;
- private Predicate<Image> imageCondition;
- private Function<Iterable<? extends Image>, Image> imageChooserFunction;
- /** this is the last options instance set by a call to options(TemplateOptions) */
- private TemplateOptions options;
- /** these are extra options that we want _added_, in order, on top of the last options set */
- private List<TemplateOptions> additionalOptions = new ArrayList<TemplateOptions>();
-
- @Override
- public T any() {
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.any(); }});
- return (T)this;
- }
-
- @Override
- public T fromHardware(final Hardware hardware) {
- this.hardware = hardware;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.fromHardware(hardware); }});
- return (T)this;
- }
-
- public Hardware getHardware() {
- return hardware;
- }
-
- @Override
- public T fromImage(final Image image) {
- this.image = image;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.fromImage(image); }});
- return (T)this;
- }
-
- public Image getImage() {
- return image;
- }
-
- @Override
- public T fromTemplate(final Template template) {
- this.template = template;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.fromTemplate(template); }});
- return (T)this;
- }
-
- public Template getTemplate() {
- return template;
- }
-
- @Override
- public T smallest() {
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.smallest(); }});
- return (T)this;
- }
-
- @Override
- public T fastest() {
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.fastest(); }});
- return (T)this;
- }
-
- @Override
- public T biggest() {
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.biggest(); }});
- return (T)this;
- }
-
- @Override
- public T locationId(final String locationId) {
- this.locationId = locationId;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.locationId(locationId); }});
- return (T)this;
- }
-
- public String getLocationId() {
- return locationId;
- }
-
- @Override
- public T imageId(final String imageId) {
- this.imageId = imageId;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.imageId(imageId); }});
- return (T)this;
- }
-
- public String getImageId() {
- return imageId;
- }
-
- @Override
- public T hardwareId(final String hardwareId) {
- this.hardwareId = hardwareId;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.hardwareId(hardwareId); }});
- return (T)this;
- }
-
- public String getHardwareId() {
- return hardwareId;
- }
-
- @Override
- public T osNameMatches(final String osNameRegex) {
- this.osNameRegex = osNameRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.osNameMatches(osNameRegex); }});
- return (T)this;
- }
-
- public String getOsNameMatchesRegex() {
- return osNameRegex;
- }
-
- @Override
- public T osDescriptionMatches(final String osDescriptionRegex) {
- this.osDescriptionRegex = osDescriptionRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.osDescriptionMatches(osDescriptionRegex); }});
- return (T)this;
- }
-
- public String getOsDescriptionMatchesRegex() {
- return osDescriptionRegex;
- }
-
- @Override
- public T osVersionMatches(final String osVersionRegex) {
- this.osVersionRegex = osVersionRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.osVersionMatches(osVersionRegex); }});
- return (T)this;
- }
-
- public String getOsVersionMatchesRegex() {
- return osVersionRegex;
- }
-
- @Override
- public T osArchMatches(final String osArchitectureRegex) {
- this.osArchitectureRegex = osArchitectureRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.osArchMatches(osArchitectureRegex); }});
- return (T)this;
- }
-
- public String getOsArchitectureMatchesRegex() {
- return osArchitectureRegex;
- }
-
- @Override
- public T os64Bit(final boolean is64bit) {
- this.is64bit = is64bit;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.os64Bit(is64bit); }});
- return (T)this;
- }
-
- public Boolean getIs64bit() {
- return is64bit;
- }
-
- @Override
- public T osFamily(final OsFamily os) {
- this.os = os;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.osFamily(os); }});
- return (T)this;
- }
-
- public OsFamily getOsFamily() {
- return os;
- }
-
- @Override
- public T hypervisorMatches(final String hypervisorRegex) {
- this.hypervisorRegex = hypervisorRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.hypervisorMatches(hypervisorRegex); }});
- return (T)this;
- }
-
- public String getHypervisorMatchesRegex() {
- return hypervisorRegex;
- }
-
- @Override
- public T imageNameMatches(final String imageNameRegex) {
- this.imageNameRegex = imageNameRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.imageNameMatches(imageNameRegex); }});
- return (T)this;
- }
-
- public String getImageNameMatchesRegex() {
- return imageNameRegex;
- }
-
- @Override
- public T imageDescriptionMatches(final String imageDescriptionRegex) {
- this.imageDescriptionRegex = imageDescriptionRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.imageDescriptionMatches(imageDescriptionRegex); }});
- return (T)this;
- }
-
- public String getImageDescriptionMatchesRegex() {
- return imageDescriptionRegex;
- }
-
- @Override
- public T imageVersionMatches(final String imageVersionRegex) {
- this.imageVersionRegex = imageVersionRegex;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.imageVersionMatches(imageVersionRegex); }});
- return (T)this;
- }
-
- public String getImageVersionMatchesRegex() {
- return imageVersionRegex;
- }
-
- @Override
- public T imageMatches(final Predicate<Image> condition) {
- this.imageCondition = condition;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.imageMatches(condition); }});
- return (T)this;
- }
-
- public Predicate<Image> getImageMatchesCondition() {
- return imageCondition;
- }
-
- @Override
- public T minCores(final double minCores) {
- this.minCores = minCores;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.minCores(minCores); }});
- return (T)this;
- }
-
- public Double getMinCores() {
- return minCores;
- }
-
- @Override
- public T minRam(final int megabytes) {
- this.minRam = megabytes;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.minRam(megabytes); }});
- return (T)this;
- }
-
- /** megabytes */
- public Integer getMinRam() {
- return minRam;
- }
-
- @Override
- public T minDisk(final double gigabytes) {
- this.minDisk = gigabytes;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.minDisk(gigabytes); }});
- return (T)this;
- }
-
- /** megabytes */
- public Double getMinDisk() {
- return minDisk;
- }
-
- public T imageChooser(final Function<Iterable<? extends Image>, Image> imageChooserFunction) {
- this.imageChooserFunction = imageChooserFunction;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.imageChooser(imageChooserFunction); }});
- return (T)this;
- }
-
- public Function<Iterable<? extends Image>, Image> imageChooser() {
- return imageChooserFunction;
- }
-
- /** clears everything set in this template, including any default from the compute service */
- // not sure this is that useful, as the default is only applied if there are no changes
- public T blank() {
- hardware = null;
- image = null;
- template = null;
- hypervisorRegex = null;
- os = null;
- locationId = null;
- imageId = null;
- hardwareId = null;
- osNameRegex = null;
- osDescriptionRegex = null;
- osVersionRegex = null;
- osArchitectureRegex = null;
- is64bit = null;
- imageNameRegex = null;
- imageDescriptionRegex = null;
- imageVersionRegex = null;
- imageCondition = null;
- minCores = null;
- minRam = null;
- options = null;
- additionalOptions.clear();
-
- // clear all fields, and commands
- commands.clear();
- // then add a command to clear osName + Version + 64bit
- osFamily(null);
- osVersionMatches(null);
- // no way to turn off 64-bitness, but it won't usually be turned on
-// os64bit(null);
- // set _something_ to prevent the default from applying
- minRam(1);
-
- return (T)this;
- }
-
- /** true if the templateBuilder spec is blank (ignoring customization options e.g. tags for the resulting instance) */
- public boolean isBlank() {
- if (commands.isEmpty()) return true;
- //also "blank" if we've blanked it
- if (commands.size()==1 && (minRam!=null && minRam==1)) return true;
- return false;
- }
-
- @Override
- public T options(final TemplateOptions options) {
- this.options = options;
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.options(options); }});
- return (T)this;
- }
-
- /** sets customization options; may be null if not set. use addOptions(new TemplateOptions()) to set new ones. */
- public TemplateOptions getOptions() {
- return options;
- }
-
- /** adds customization options; if options have already been set, this will additively set selected options
- * (but not all, see addTemplateOptions for more info)
- */
- public T addOptions(final TemplateOptions options) {
- this.additionalOptions.add(options);
- commands.add(new Function<TemplateBuilder,TemplateBuilder>() {
- public TemplateBuilder apply(TemplateBuilder b) { return b.options(options); }});
- return (T)this;
- }
-
- public List<TemplateOptions> getAdditionalOptions() {
- return ImmutableList.copyOf(additionalOptions);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(
- hypervisorRegex,
- os,
- locationId,
- hardwareId,
- imageId,
- imageDescriptionRegex,
- imageNameRegex,
- imageVersionRegex,
- // might not be implement hashCode, so ignore
-// imageCondition,
-// imageChooserFunction,
- is64bit,
- locationId,
- osArchitectureRegex,
- osDescriptionRegex,
- osNameRegex,
- osVersionRegex,
- minCores,
- minRam,
- minDisk,
- options,
- additionalOptions,
- // might not implement hashCode, so ignore
-// template,
- 0);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- AbstractPortableTemplateBuilder other = (AbstractPortableTemplateBuilder) obj;
- if (!Objects.equal(additionalOptions, other.additionalOptions)) return false;
- if (!Objects.equal(commands, other.commands)) return false;
- if (!Objects.equal(locationId, other.locationId)) return false;
- if (!Objects.equal(hardware, other.hardware)) return false;
- if (!Objects.equal(hardwareId, other.hardwareId)) return false;
- if (!Objects.equal(image, other.image)) return false;
- if (!Objects.equal(imageId, other.imageId)) return false;
- if (!Objects.equal(imageDescriptionRegex, other.imageDescriptionRegex)) return false;
- if (!Objects.equal(imageNameRegex, other.imageNameRegex)) return false;
- if (!Objects.equal(imageVersionRegex, other.imageVersionRegex)) return false;
- if (!Objects.equal(imageCondition, other.imageCondition)) return false;
- if (!Objects.equal(imageChooserFunction, other.imageChooserFunction)) return false;
- if (!Objects.equal(os, other.os)) return false;
- if (!Objects.equal(osArchitectureRegex, other.osArchitectureRegex)) return false;
- if (!Objects.equal(osDescriptionRegex, other.osDescriptionRegex)) return false;
- if (!Objects.equal(osNameRegex, other.osNameRegex)) return false;
- if (!Objects.equal(osVersionRegex, other.osVersionRegex)) return false;
- if (!Objects.equal(is64bit, other.is64bit)) return false;
- if (!Objects.equal(hypervisorRegex, other.hypervisorRegex)) return false;
- if (!Objects.equal(minCores, other.minCores)) return false;
- if (!Objects.equal(minRam, other.minRam)) return false;
- if (!Objects.equal(minDisk, other.minDisk)) return false;
- if (!Objects.equal(options, other.options)) return false;
- if (!Objects.equal(template, other.template)) return false;
- return true;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName()+"["+makeNonTrivialArgumentsString()+"]";
- }
-
- protected String makeNonTrivialArgumentsString() {
- String s =
- (hardware != null ? "hardware=" + hardware + ", " : "")
- + (image != null ? "image=" + image + ", " : "")
- + (template != null ? "template=" + template + ", " : "")
- + (hypervisorRegex != null ? "hypervisorRegex="
- + hypervisorRegex + ", " : "")
- + (os != null ? "os=" + os + ", " : "")
- + (locationId != null ? "locationId=" + locationId + ", " : "")
- + (imageId != null ? "imageId=" + imageId + ", " : "")
- + (hardwareId != null ? "hardwareId=" + hardwareId + ", " : "")
- + (osNameRegex != null ? "osNameRegex=" + osNameRegex + ", "
- : "")
- + (osDescriptionRegex != null ? "osDescriptionRegex="
- + osDescriptionRegex + ", " : "")
- + (osVersionRegex != null ? "osVersionRegex=" + osVersionRegex
- + ", " : "")
- + (osArchitectureRegex != null ? "osArchictectureRegex="
- + osArchitectureRegex + ", " : "")
- + (is64bit != null ? "is64bit=" + is64bit + ", " : "")
- + (imageNameRegex != null ? "imageNameRegex=" + imageNameRegex
- + ", " : "")
- + (imageDescriptionRegex != null ? "imageDescriptionRegex="
- + imageDescriptionRegex + ", " : "")
- + (imageVersionRegex != null ? "imageVersionRegex="
- + imageVersionRegex + ", " : "")
- + (imageCondition != null ? "imageCondition=" + imageCondition
- + ", " : "")
- + (imageChooserFunction != null ? "imageChooserFunction=" + imageChooserFunction
- + ", " : "")
- + (minCores != null ? "minCores=" + minCores + ", " : "")
- + (minRam != null ? "minRam=" + minRam + ", " : "")
- + (minDisk != null ? "minDisk=" + minDisk + ", " : "");
- if (s.endsWith(", ")) s = s.substring(0, s.length()-2);
- return s;
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/PortableTemplateBuilder.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/PortableTemplateBuilder.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/PortableTemplateBuilder.java
deleted file mode 100644
index 3baa003..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/templates/PortableTemplateBuilder.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.templates;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.jclouds.compute.ComputeService;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.compute.domain.TemplateBuilder;
-import org.jclouds.compute.domain.TemplateBuilderSpec;
-import org.jclouds.compute.options.TemplateOptions;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.primitives.Ints;
-
-
-public class PortableTemplateBuilder<T extends PortableTemplateBuilder<?>> extends AbstractPortableTemplateBuilder<T> {
-
- ComputeService svc;
- List<TemplateOptions> additionalOptionalOptions = new ArrayList<TemplateOptions>();
-
- @Override
- public synchronized Template build() {
- if (svc!=null) return newJcloudsTemplate(svc);
- throw new IllegalStateException("Cannot build a portable template until a compute service is attached");
- }
-
- public synchronized ComputeService attachComputeService(ComputeService svc) {
- ComputeService old = this.svc;
- this.svc = svc;
- return old;
- }
-
- public TemplateBuilder newJcloudsTemplateBuilder(ComputeService svc) {
- TemplateBuilder tb = svc.templateBuilder();
- for (Function<TemplateBuilder,TemplateBuilder> c: commands) {
- tb = c.apply(tb);
- }
-
- tb.options(computeAggregatedOptions(true));
-
- return tb;
- }
-
- public Template newJcloudsTemplate(ComputeService svc) {
- return newJcloudsTemplateBuilder(svc).build();
- }
-
- /** Adds template options which are used for building, but not for matching/filtering.
- * (eg tags added here will be set on any machine created by this template,
- * but will not be required when matching this template to existing machines) */
- @SuppressWarnings("unchecked")
- public T addOptionalOptions(TemplateOptions options) {
- additionalOptionalOptions.add(options);
- return (T)this;
- }
-
- protected TemplateOptions computeAggregatedOptions(boolean includeOptional) {
- TemplateOptions result;
- if (getOptions()!=null) result = getOptions().clone();
- else result = new TemplateOptions();
- if (includeOptional)
- for (TemplateOptions moreOptions: getAdditionalOptionalOptions()) result = addTemplateOptions(result, moreOptions);
- for (TemplateOptions moreOptions: getAdditionalOptions()) result = addTemplateOptions(result, moreOptions);
- return result;
- }
-
- public List<TemplateOptions> getAdditionalOptionalOptions() {
- return ImmutableList.copyOf(additionalOptionalOptions);
- }
-
- /** like TemplateOptions.copyTo but additive wrt arrays, collections, and maps,
- * putting moreOptions in on top of / at the end of options.
- * currently applies to inboundPorts, tags, and userMetadata. */
- public static TemplateOptions addTemplateOptions(TemplateOptions options, TemplateOptions moreOptions) {
- TemplateOptions result = options.clone();
- moreOptions.copyTo(result);
-
- Set<String> tags = new LinkedHashSet<String>(options.getTags());
- tags.addAll(moreOptions.getTags());
- result.tags(tags);
-
- Map<String,String> userMetadata = new LinkedHashMap<String,String>(options.getUserMetadata());
- userMetadata.putAll(moreOptions.getUserMetadata());
- result.userMetadata(userMetadata);
-
- Set<Integer> inboundPorts = new TreeSet<Integer>();
- for (int port: options.getInboundPorts()) inboundPorts.add(port);
- for (int port: moreOptions.getInboundPorts()) inboundPorts.add(port);
- int[] inboundPortsArray = new int[inboundPorts.size()];
- int i=0;
- for (Iterator<Integer> portI=inboundPorts.iterator(); portI.hasNext();) {
- inboundPortsArray[i++] = portI.next();
- }
- result.inboundPorts(inboundPortsArray);
-
- return result;
- }
-
- protected String makeNonTrivialArgumentsString() {
- String s = super.makeNonTrivialArgumentsString();
- TemplateOptions aggr = computeAggregatedOptions(false);
- if (aggr.getInboundPorts().length>0) s = "ports="+Ints.asList(aggr.getInboundPorts())+(s!=null && s.length()>0 ? ", "+s : "");
- if (!aggr.getUserMetadata().isEmpty()) s = "metadata="+aggr.getUserMetadata()+(s!=null && s.length()>0 ? ", "+s : "");
- if (!aggr.getTags().isEmpty()) s = "tags="+aggr.getTags()+(s!=null && s.length()>0 ? ", "+s : "");
- return s;
- }
-
- @Override
- public TemplateBuilder from(TemplateBuilderSpec spec) {
- TemplateOptions options = new TemplateOptions();
- addOptionalOptions(options);
- TemplateBuilder result = spec.copyTo(this, options);
- return result;
- }
-
- @Override
- public TemplateBuilder from(String spec) {
- return from(TemplateBuilderSpec.parse(spec));
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtension.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtension.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtension.java
deleted file mode 100644
index 20bfb4c..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/zone/AwsAvailabilityZoneExtension.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.zone;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.List;
-import java.util.Set;
-
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.jclouds.aws.ec2.AWSEC2Api;
-import org.jclouds.ec2.domain.AvailabilityZoneInfo;
-
-import brooklyn.location.Location;
-import brooklyn.location.cloud.AbstractAvailabilityZoneExtension;
-import brooklyn.location.cloud.AvailabilityZoneExtension;
-import brooklyn.location.jclouds.JcloudsLocation;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-public class AwsAvailabilityZoneExtension extends AbstractAvailabilityZoneExtension implements AvailabilityZoneExtension {
-
- private final JcloudsLocation loc;
-
- public AwsAvailabilityZoneExtension(ManagementContext managementContext, JcloudsLocation loc) {
- super(managementContext);
- this.loc = checkNotNull(loc, "loc");
- checkArgument(loc.getProvider().equals("aws-ec2"), "provider not aws-ec2 (%s)", loc.getProvider());
- }
-
- @Override
- protected List<Location> doGetAllSubLocations() {
- List<Location> result = Lists.newArrayList();
- Set<AvailabilityZoneInfo> zones = getAvailabilityZones();
- for (AvailabilityZoneInfo zone : zones) {
- result.add(newSubLocation(loc, zone));
- }
- return result;
- }
-
- @Override
- protected boolean isNameMatch(Location loc, Predicate<? super String> namePredicate) {
- return namePredicate.apply(((JcloudsLocation)loc).getRegion());
- }
-
- protected Set<AvailabilityZoneInfo> getAvailabilityZones() {
- String regionName = loc.getRegion();
- AWSEC2Api ec2Client = loc.getComputeService().getContext().unwrapApi(AWSEC2Api.class);
- return ec2Client.getAvailabilityZoneAndRegionApi().get().describeAvailabilityZonesInRegion(regionName);
- }
-
- protected JcloudsLocation newSubLocation(Location parent, AvailabilityZoneInfo zone) {
- return loc.newSubLocation(ImmutableMap.of(JcloudsLocation.CLOUD_REGION_ID, zone.getZone()));
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java b/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
index f0d1140..bd02f60 100644
--- a/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
+++ b/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
@@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory;
import brooklyn.entity.basic.AbstractEntity;
import brooklyn.event.basic.Sensors;
-import brooklyn.location.Location;
-import brooklyn.location.basic.WinRmMachineLocation;
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.location.basic.WinRmMachineLocation;
import brooklyn.policy.basic.AbstractPolicy;
import com.google.common.annotations.Beta;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java b/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
index 2459187..4e2f68c 100644
--- a/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
+++ b/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
@@ -37,8 +37,8 @@ import brooklyn.entity.basic.AbstractEntity;
import brooklyn.entity.basic.ConfigKeys;
import brooklyn.entity.basic.EntityInternal;
import brooklyn.event.basic.Sensors;
-import brooklyn.location.Location;
-import brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.Location;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
import brooklyn.policy.basic.AbstractPolicy;
import brooklyn.util.flags.SetFromFlag;
import brooklyn.util.internal.ssh.SshTool;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsSubnetSshMachineLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsSubnetSshMachineLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsSubnetSshMachineLocation.java
new file mode 100644
index 0000000..c21810d
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsSubnetSshMachineLocation.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import java.util.Map;
+
+import org.jclouds.compute.domain.NodeMetadata;
+
+import org.apache.brooklyn.location.basic.SupportsPortForwarding.RequiresPortForwarding;
+
+public abstract class AbstractJcloudsSubnetSshMachineLocation extends JcloudsSshMachineLocation implements RequiresPortForwarding {
+
+ public AbstractJcloudsSubnetSshMachineLocation() {
+ }
+
+ /** @deprecated since 0.6.0 use no-arg constructor, as per parent */
+ @Deprecated
+ public AbstractJcloudsSubnetSshMachineLocation(Map flags, JcloudsLocation parent, NodeMetadata node) {
+ super(flags, parent, node);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java
new file mode 100644
index 0000000..e73d5f7
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BasicJcloudsLocationCustomizer.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.options.TemplateOptions;
+
+import com.google.common.annotations.Beta;
+
+
+/**
+ * A default no-op implementation, which can be extended to override the appropriate methods.
+ *
+ * Sub-classing will give the user some protection against future API changes - note that
+ * {@link JcloudsLocationCustomizer} is marked {@link Beta}.
+ *
+ * @author aled
+ */
+public class BasicJcloudsLocationCustomizer implements JcloudsLocationCustomizer {
+
+ @Override
+ public void customize(JcloudsLocation location, ComputeService computeService, TemplateBuilder templateBuilder) {
+ // no-op
+ }
+
+ @Override
+ public void customize(JcloudsLocation location, ComputeService computeService, Template template) {
+ // no-op
+ }
+
+ @Override
+ public void customize(JcloudsLocation location, ComputeService computeService, TemplateOptions templateOptions) {
+ // no-op
+ }
+
+ @Override
+ public void customize(JcloudsLocation location, ComputeService computeService, JcloudsMachineLocation machine) {
+ if (machine instanceof JcloudsSshMachineLocation) {
+ customize(location, computeService, (JcloudsSshMachineLocation)machine);
+ } else {
+ // no-op
+ }
+ }
+
+ @Override
+ public void preRelease(JcloudsMachineLocation machine) {
+ if (machine instanceof JcloudsSshMachineLocation) {
+ preRelease((JcloudsSshMachineLocation)machine);
+ } else {
+ // no-op
+ }
+ }
+
+ @Override
+ public void postRelease(JcloudsMachineLocation machine) {
+ if (machine instanceof JcloudsSshMachineLocation) {
+ postRelease((JcloudsSshMachineLocation)machine);
+ } else {
+ // no-op
+ }
+ }
+
+ @Override
+ @Deprecated
+ public void customize(JcloudsLocation location, ComputeService computeService, JcloudsSshMachineLocation machine) {
+ // no-op
+ }
+
+ @Override
+ @Deprecated
+ public void preRelease(JcloudsSshMachineLocation machine) {
+ // no-op
+ }
+
+ @Override
+ @Deprecated
+ public void postRelease(JcloudsSshMachineLocation machine) {
+ // no-op
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynImageChooser.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynImageChooser.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynImageChooser.java
new file mode 100644
index 0000000..62cf003
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynImageChooser.java
@@ -0,0 +1,367 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.collections.MutableList;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
+import com.google.common.math.DoubleMath;
+
+@Beta
+/** NB: subclasses must implement {@link #clone()} */
+public class BrooklynImageChooser implements Cloneable {
+
+ private static final Logger log = LoggerFactory.getLogger(BrooklynImageChooser.class);
+
+ protected ComputeService computeService;
+ protected String cloudProviderName;
+
+ protected static int compare(double left, double right) {
+ return DoubleMath.fuzzyCompare(left, right, 0.00000001);
+ }
+
+ protected static boolean imageNameContains(Image img, String pattern) {
+ if (img.getName()==null) return false;
+ return img.getName().contains(pattern);
+ }
+
+ protected static boolean imageNameContainsCaseInsensitive(Image img, String pattern) {
+ if (img.getName()==null) return false;
+ return img.getName().toLowerCase().contains(pattern.toLowerCase());
+ }
+
+ protected static boolean imageNameContainsWordCaseInsensitive(Image img, String pattern) {
+ if (img.getName()==null) return false;
+ return img.getName().toLowerCase().matches("(.*[^a-z])?"+pattern.toLowerCase()+"([^a-z].*)?");
+ }
+
+ public double punishmentForOldOsVersions(Image img, OsFamily family, double minVersion) {
+ OperatingSystem os = img.getOperatingSystem();
+ if (os!=null && family.equals(os.getFamily())) {
+ String v = os.getVersion();
+ if (v!=null) {
+ try {
+ double vd = Double.parseDouble(v);
+ // punish older versions, with a -log function (so 0.5 version behind is -log(1.5)=-0.5 and 2 versions behind is -log(3)=-1.2
+ if (vd < minVersion) return -Math.log(1+(minVersion - vd));
+ } catch (Exception e) {
+ /* ignore unparseable versions */
+ }
+ }
+ }
+ return 0;
+ }
+
+ public List<String> blackListedImageIds() {
+ return Arrays.asList(
+ // bad natty image - causes 403 on attempts to apt-get; https://bugs.launchpad.net/ubuntu/+bug/987182
+ "us-east-1/ami-1cb30875",
+ // wrong login user advertised, causes "Error Invalid packet: indicated length 1349281121 too large"
+ // from sshj due to message coming back "Plea"(se log in as another user), according to https://github.com/jclouds/legacy-jclouds/issues/748
+ "us-east-1/ami-08faa660"
+ );
+ }
+
+ public List<String> whilelistedImageIds() {
+ return Arrays.asList(
+ // these are the ones we recommend in brooklyn.properties, but now autodetection should be more reliable
+// "us-east-1/ami-d0f89fb9",
+// "us-west-1/ami-fe002cbb",
+// "us-west-2/ami-70f96e40",
+// "eu-west-1/ami-ce7b6fba",
+// "sa-east-1/ami-a3da00be",
+// "ap-southeast-1/ami-64084736",
+// "ap-southeast-2/ami-04ea7a3e",
+// "ap-northeast-1/ami-fe6ceeff"
+ );
+ }
+
+ public double score(Image img) {
+ double score = 0;
+
+ if (blackListedImageIds().contains(img.getId()))
+ score -= 50;
+
+ if (whilelistedImageIds().contains(img.getId()))
+ // NB: this should be less than deprecated punishment to catch deprecation of whitelisted items
+ score += 20;
+
+ score += punishmentForDeprecation(img);
+
+
+ // prefer these guys, in stock brooklyn provisioning
+ score += punishmentForOldOsVersions(img, OsFamily.UBUNTU, 11);
+ score += punishmentForOldOsVersions(img, OsFamily.CENTOS, 6);
+
+ OperatingSystem os = img.getOperatingSystem();
+ if (os!=null) {
+ if (os.getFamily()!=null) {
+ // preference for these open, popular OS (but only wrt versions above)
+ if (os.getFamily().equals(OsFamily.CENTOS)) score += 2;
+ else if (os.getFamily().equals(OsFamily.UBUNTU)) {
+ score += 2;
+
+ // prefer these LTS releases slightly above others (including above CentOS)
+ // (but note in AWS Virginia, at least, version is empty for the 14.04 images for some reason, as of Aug 2014)
+ if ("14.04".equals(os.getVersion())) score += 0.2;
+ else if ("12.04".equals(os.getVersion())) score += 0.1;
+
+ // NB some 13.10 images take 20m+ before they are sshable on AWS
+ // with "vesafb: module verification error" showing in the AWS system log
+ }
+
+ // slight preference for these
+ else if (os.getFamily().equals(OsFamily.RHEL)) score += 1;
+ else if (os.getFamily().equals(OsFamily.AMZN_LINUX)) score += 1;
+ else if (os.getFamily().equals(OsFamily.DEBIAN)) score += 1;
+
+ // prefer to take our chances with unknown / unlabelled linux than something explicitly windows
+ else if (os.getFamily().equals(OsFamily.WINDOWS)) score -= 1;
+
+ if ("softlayer".equals(cloudProviderName)) {
+ // on softlayer, prefer images where family is part of the image id
+ // (this is the only way to identiy official images; but in other clouds
+ // it can cause not-so-good images to get selected!)
+ if (img.getId().toLowerCase().indexOf(os.getFamily().toString().toLowerCase()) >= 0)
+ score += 0.5;
+ }
+ }
+ // prefer 64-bit
+ if (os.is64Bit()) score += 0.5;
+ }
+
+ // TODO prefer known providerIds
+
+ if (log.isTraceEnabled())
+ log.trace("initial score "+score+" for "+img);
+
+ return score;
+ }
+
+ protected double punishmentForDeprecation(Image img) {
+ // google deprecation strategy
+ // userMetadata={deprecatedState=DEPRECATED}}
+ String deprecated = img.getUserMetadata().get("deprecatedState");
+ if (deprecated!=null) {
+ if ("deprecated".equalsIgnoreCase(deprecated))
+ return -30;
+ log.warn("Unrecognised 'deprecatedState' value '"+deprecated+"' when scoring "+img+"; ignoring that metadata");
+ }
+
+ // common strategies
+ if (imageNameContainsWordCaseInsensitive(img, "deprecated")) return -30;
+ if (imageNameContainsWordCaseInsensitive(img, "alpha")) return -10;
+ if (imageNameContainsWordCaseInsensitive(img, "beta")) return -5;
+ if (imageNameContainsWordCaseInsensitive(img, "testing")) return -5;
+ if (imageNameContainsWordCaseInsensitive(img, "rc")) return -3;
+
+ // no indication this is deprecated
+ return 0;
+ }
+
+ public BrooklynImageChooser clone() {
+ return new BrooklynImageChooser();
+ }
+
+ protected void use(ComputeService service) {
+ if (this.computeService!=null && !this.computeService.equals(service))
+ throw new IllegalStateException("ImageChooser must be cloned to set a compute service");
+ this.computeService = service;
+ if (computeService!=null) {
+ cloudProviderName = computeService.getContext().unwrap().getId();
+ }
+ }
+
+ public BrooklynImageChooser cloneFor(ComputeService service) {
+ BrooklynImageChooser result = clone();
+ result.use(service);
+ return result;
+ }
+
+ public static class OrderingScoredWithoutDefaults extends Ordering<Image> implements ComputeServiceAwareChooser<OrderingScoredWithoutDefaults> {
+ private BrooklynImageChooser chooser;
+ public OrderingScoredWithoutDefaults(BrooklynImageChooser chooser) {
+ this.chooser = chooser;
+ }
+ public int compare(Image left, Image right) {
+ return BrooklynImageChooser.compare(chooser.score(left), chooser.score(right));
+ }
+ @Override
+ public OrderingScoredWithoutDefaults cloneFor(ComputeService service) {
+ return new OrderingScoredWithoutDefaults(chooser.cloneFor(service));
+ }
+ }
+
+ public Ordering<Image> orderingScoredWithoutDefaults() {
+ return new OrderingScoredWithoutDefaults(this);
+ }
+
+ /** @deprecated since 0.7.0 kept in case persisted */
+ @Deprecated
+ public Ordering<Image> orderingScoredWithoutDefaultsDeprecated() {
+ return new Ordering<Image>() {
+ @Override
+ public int compare(Image left, Image right) {
+ return BrooklynImageChooser.compare(score(left), score(right));
+ }
+ };
+ }
+
+ public static class OrderingWithDefaults extends Ordering<Image> implements ComputeServiceAwareChooser<OrderingWithDefaults> {
+ Ordering<Image> primaryOrdering;
+ public OrderingWithDefaults(final Ordering<Image> primaryOrdering) {
+ this.primaryOrdering = primaryOrdering;
+ }
+ @Override
+ public int compare(Image left, Image right) {
+ return ComparisonChain.start()
+ .compare(left, right, primaryOrdering)
+ // fall back to default strategy otherwise, except preferring *non*-null values
+ // TODO use AlphaNum string comparator
+ .compare(left.getName(), right.getName(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getVersion(), right.getVersion(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getDescription(), right.getDescription(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch(), Ordering.<String> natural().nullsFirst()).result();
+ }
+ @Override
+ public OrderingWithDefaults cloneFor(ComputeService service) {
+ if (primaryOrdering instanceof ComputeServiceAwareChooser) {
+ return new OrderingWithDefaults( BrooklynImageChooser.cloneFor(primaryOrdering, service) );
+ }
+ return this;
+ }
+ }
+
+ public static Ordering<Image> orderingWithDefaults(final Ordering<Image> primaryOrdering) {
+ return new OrderingWithDefaults(primaryOrdering);
+ }
+
+ /** @deprecated since 0.7.0 kept in case persisted */
+ @Deprecated
+ public static Ordering<Image> orderingWithDefaultsDeprecated(final Ordering<Image> primaryOrdering) {
+ return new Ordering<Image>() {
+ @Override
+ public int compare(Image left, Image right) {
+ return ComparisonChain.start()
+ .compare(left, right, primaryOrdering)
+ // fall back to default strategy otherwise, except preferring *non*-null values
+ // TODO use AlphaNum string comparator
+ .compare(left.getName(), right.getName(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getVersion(), right.getVersion(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getDescription(), right.getDescription(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(), Ordering.<String> natural().nullsFirst())
+ .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch(), Ordering.<String> natural().nullsFirst()).result();
+ }
+ };
+ }
+
+ public static class ImageChooserFromOrdering implements Function<Iterable<? extends Image>, Image>, ComputeServiceAwareChooser<ImageChooserFromOrdering> {
+ final Ordering<Image> ordering;
+ public ImageChooserFromOrdering(final Ordering<Image> ordering) { this.ordering = ordering; }
+ @Override
+ public Image apply(Iterable<? extends Image> input) {
+ List<? extends Image> maxImages = multiMax(ordering, input);
+ return maxImages.get(maxImages.size() - 1);
+ }
+ @Override
+ public ImageChooserFromOrdering cloneFor(ComputeService service) {
+ if (ordering instanceof ComputeServiceAwareChooser) {
+ return new ImageChooserFromOrdering( BrooklynImageChooser.cloneFor(ordering, service) );
+ }
+ return this;
+ }
+ }
+
+ public static Function<Iterable<? extends Image>, Image> imageChooserFromOrdering(final Ordering<Image> ordering) {
+ return new ImageChooserFromOrdering(ordering);
+ }
+
+ /** @deprecated since 0.7.0 kept in case persisted */
+ @Deprecated
+ public static Function<Iterable<? extends Image>, Image> imageChooserFromOrderingDeprecated(final Ordering<Image> ordering) {
+ return new Function<Iterable<? extends Image>, Image>() {
+ @Override
+ public Image apply(Iterable<? extends Image> input) {
+ List<? extends Image> maxImages = multiMax(ordering, input);
+ return maxImages.get(maxImages.size() - 1);
+ }
+ };
+ }
+
+ protected interface ComputeServiceAwareChooser<T> {
+ public T cloneFor(ComputeService service);
+ }
+
+ /** Attempts to clone the given item for use with the given {@link ComputeService}, if
+ * the item is {@link ComputeServiceAwareChooser}; otherwise it returns the item unchanged */
+ @SuppressWarnings("unchecked")
+ public static <T> T cloneFor(T item, ComputeService service) {
+ if (item instanceof ComputeServiceAwareChooser) {
+ return ((ComputeServiceAwareChooser<T>)item).cloneFor(service);
+ }
+ return item;
+ }
+
+ // from jclouds
+ static <T, E extends T> List<E> multiMax(Comparator<T> ordering, Iterable<E> iterable) {
+ Iterator<E> iterator = iterable.iterator();
+ List<E> maxes = MutableList.of(iterator.next());
+ E maxSoFar = maxes.get(0);
+ while (iterator.hasNext()) {
+ E current = iterator.next();
+ int comparison = ordering.compare(maxSoFar, current);
+ if (comparison == 0) {
+ maxes.add(current);
+ } else if (comparison < 0) {
+ maxes = MutableList.of(current);
+ maxSoFar = current;
+ }
+ }
+ return maxes;
+ }
+
+ public Ordering<Image> ordering() {
+ return orderingWithDefaults(orderingScoredWithoutDefaults());
+ }
+
+ public Function<Iterable<? extends Image>,Image> chooser() {
+ return imageChooserFromOrdering(ordering());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java
new file mode 100644
index 0000000..e857e93
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import static org.apache.brooklyn.location.jclouds.pool.MachinePoolPredicates.matching;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.management.Task;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.location.MachineLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.jclouds.pool.MachinePool;
+import org.apache.brooklyn.location.jclouds.pool.MachineSet;
+import org.apache.brooklyn.location.jclouds.pool.ReusableMachineTemplate;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.task.BasicExecutionContext;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * @deprecated since 0.6.0; never used in production setting, and thus of dubious value; best avoided as unlikely to be supported in future versions
+ */
+@Deprecated
+public class BrooklynMachinePool extends MachinePool {
+
+ private static final Logger log = LoggerFactory.getLogger(BrooklynMachinePool.class);
+
+ protected final JcloudsLocation location;
+ final List<Task<?>> activeTasks = new ArrayList<Task<?>>();
+ final String providerLocationId;
+
+ public BrooklynMachinePool(JcloudsLocation l) {
+ super(l.getComputeService());
+ providerLocationId = l.getRegion();
+ this.location = l;
+ }
+
+ /** claims a machine with the indicated spec, creating if necessary */
+ public SshMachineLocation obtain(ReusableMachineTemplate t) {
+ MachineSet previous = unclaimed(matching(t));
+
+ while (true) {
+ NodeMetadata m = claim(1, t).iterator().next();
+ // TODO ideally shouldn't have to rebind
+ SshMachineLocation result = null;
+ try {
+ result = toSshMachineLocation( m );
+ } catch (Exception e) {
+ if (previous.contains(m)) {
+ log.debug("attempt to bind to previous existing machine "+m+" failed (will blacklist and retry another): "+e);
+ } else {
+ log.warn("attempt to bind to machine "+m+" failed: "+e);
+ throw Throwables.propagate(e);
+ }
+ }
+ if (result!=null) return result;
+ if (previous.contains(m)) {
+ log.debug("could not bind to previous existing machine "+m+"; blacklisting and trying a new one");
+ addToBlacklist(new MachineSet(m));
+ } else {
+ throw new IllegalStateException("cannot bind/connect to newly created machine; error in configuration");
+ }
+ }
+ }
+
+ protected MachineSet filterForAllowedMachines(MachineSet input) {
+ MachineSet result = super.filterForAllowedMachines(input);
+ if (providerLocationId!=null) {
+ result = result.filtered(matching( new ReusableMachineTemplate().locationId(providerLocationId).strict(false) ));
+ }
+ return result;
+ }
+
+ /** returns an SshMachineLocation, if one can be created and accessed; returns null if it cannot be created */
+ protected SshMachineLocation toSshMachineLocation(NodeMetadata m) {
+ try {
+ JcloudsSshMachineLocation sshM = location.rebindMachine(m);
+ if (sshM.execCommands("check-reachable", Arrays.asList("whoami")) != 0) {
+ log.warn("cannot bind to machine "+m);
+ return null;
+ }
+ return sshM;
+ } catch (Exception e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ @Override
+ public MachineSet create(int count, ReusableMachineTemplate template) {
+ List<NodeMetadata> nodes = new ArrayList<NodeMetadata>();
+ for (int i=0; i<count; i++) {
+ // TODO this in parallel
+ JcloudsSshMachineLocation m;
+ try {
+ MachineLocation machineLocation = location.obtain(MutableMap.of("callerContext", ""+this+"("+template+")"), template);
+ // Class has been deprecated since 0.6.0, and prior to that, obtain would have returned a JcloudsSshMachineLocation
+ if (machineLocation instanceof JcloudsSshMachineLocation) {
+ m = (JcloudsSshMachineLocation) machineLocation;
+ } else {
+ throw new UnsupportedOperationException("Cannot create WinRmMachineLocation");
+ }
+ } catch (Exception e) {
+ throw Throwables.propagate(e);
+ }
+ nodes.add(m.getNode());
+ }
+ MachineSet result = new MachineSet(nodes);
+ registerNewNodes(result, template);
+ return result;
+ }
+
+ public boolean unclaim(SshMachineLocation location) {
+ init();
+ if (location instanceof JcloudsSshMachineLocation)
+ return unclaim(new MachineSet( ((JcloudsSshMachineLocation)location).getNode()) ) > 0;
+ return false;
+ }
+ public boolean destroy(SshMachineLocation location) {
+ init();
+ if (location instanceof JcloudsSshMachineLocation)
+ return destroy(new MachineSet( ((JcloudsSshMachineLocation)location).getNode()) ) > 0;
+ return false;
+ }
+
+ // TODO we need to remove stale tasks somewhere
+ protected <T> Task<T> addTask(Task<T> t) {
+ synchronized (activeTasks) { activeTasks.add(t); }
+ return t;
+ }
+
+ public List<Task<?>> getActiveTasks() {
+ List<Task<?>> result;
+ synchronized (activeTasks) { result = ImmutableList.<Task<?>>copyOf(activeTasks); }
+ return result;
+ }
+
+ public void blockUntilTasksEnded() {
+ while (true) {
+ boolean allDone = true;
+ List<Task<?>> tt = getActiveTasks();
+ for (Task<?> t: tt) {
+ if (!t.isDone()) {
+ allDone = false;
+ if (log.isDebugEnabled()) log.debug("Pool "+this+", blocking for completion of: "+t);
+ t.blockUntilEnded();
+ }
+ }
+ synchronized (activeTasks) {
+ List<Task> newTT = new ArrayList<Task>(getActiveTasks());
+ newTT.removeAll(tt);
+ if (allDone && tt.isEmpty()) {
+ //task list has stabilized, and there are no active tasks; clear and exit
+ if (log.isDebugEnabled()) log.debug("Pool "+this+", all known tasks have completed, clearing list");
+ activeTasks.clear();
+ break;
+ }
+ if (log.isDebugEnabled()) log.debug("Pool "+this+", all previously known tasks have completed, but there are new tasks ("+newTT+") checking them");
+ }
+ }
+ }
+
+ /** starts the given template; for use only within a task (e.g. application's start effector).
+ * returns a child task of the current task.
+ * <p>
+ * throws exception if not in a task. (you will have to claim, then invoke the effectors manually.) */
+ public Task<?> start(final ReusableMachineTemplate template, final List<? extends Startable> entities) {
+ BasicExecutionContext ctx = BasicExecutionContext.getCurrentExecutionContext();
+ if (ctx==null) throw new IllegalStateException("Pool.start is only permitted within a task (effector)");
+ final AtomicReference<Task<?>> t = new AtomicReference<Task<?>>();
+ synchronized (t) {
+ t.set(ctx.submit(new Runnable() {
+ public void run() {
+ synchronized (t) {
+ if (log.isDebugEnabled()) log.debug("Pool "+this+", task "+t.get()+" claiming a "+template);
+ SshMachineLocation m = obtain(template);
+ if (log.isDebugEnabled()) log.debug("Pool "+this+", task "+t.get()+" got "+m+"; starting "+entities);
+ for (Startable entity: entities)
+ addTask( ((Entity)entity).invoke(Startable.START, MutableMap.of("locations", Arrays.asList(m))) );
+ }
+ }
+ }));
+ }
+ addTask(t.get());
+ return t.get();
+ }
+
+ /** @see #start(ReusableMachineTemplate, List) */
+ public Task<?> start(ReusableMachineTemplate template, Startable ...entities) {
+ return start(template, Arrays.asList(entities));
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java
new file mode 100644
index 0000000..a835e2c
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import org.jclouds.compute.ComputeService;
+
+import brooklyn.util.config.ConfigBag;
+
+public interface ComputeServiceRegistry {
+
+ public ComputeService findComputeService(ConfigBag conf, boolean allowReuse);
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
new file mode 100644
index 0000000..f3f39bb
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_AMI_QUERY;
+import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.brooklyn.location.cloud.CloudLocationConfig;
+import org.jclouds.Constants;
+import org.jclouds.ContextBuilder;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.ec2.reference.EC2Constants;
+import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Sanitizer;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.inject.Module;
+
+public class ComputeServiceRegistryImpl implements ComputeServiceRegistry, JcloudsLocationConfig {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ComputeServiceRegistryImpl.class);
+
+ public static final ComputeServiceRegistryImpl INSTANCE = new ComputeServiceRegistryImpl();
+
+ protected ComputeServiceRegistryImpl() {
+ }
+
+ protected final Map<Map<?,?>,ComputeService> cachedComputeServices = new ConcurrentHashMap<Map<?,?>,ComputeService>();
+
+ protected final Object createComputeServicesMutex = new Object();
+
+ @Override
+ public ComputeService findComputeService(ConfigBag conf, boolean allowReuse) {
+ String provider = checkNotNull(conf.get(CLOUD_PROVIDER), "provider must not be null");
+ String identity = checkNotNull(conf.get(CloudLocationConfig.ACCESS_IDENTITY), "identity must not be null");
+ String credential = checkNotNull(conf.get(CloudLocationConfig.ACCESS_CREDENTIAL), "credential must not be null");
+
+ Properties properties = new Properties();
+ properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, Boolean.toString(true));
+ properties.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, Boolean.toString(true));
+ properties.setProperty("jclouds.ssh.max-retries", conf.getStringKey("jclouds.ssh.max-retries") != null ?
+ conf.getStringKey("jclouds.ssh.max-retries").toString() : "50");
+ // Enable aws-ec2 lazy image fetching, if given a specific imageId; otherwise customize for specific owners; or all as a last resort
+ // See https://issues.apache.org/jira/browse/WHIRR-416
+ if ("aws-ec2".equals(provider)) {
+ // TODO convert AWS-only flags to config keys
+ if (groovyTruth(conf.get(IMAGE_ID))) {
+ properties.setProperty(PROPERTY_EC2_AMI_QUERY, "");
+ properties.setProperty(PROPERTY_EC2_CC_AMI_QUERY, "");
+ } else if (groovyTruth(conf.getStringKey("imageOwner"))) {
+ properties.setProperty(PROPERTY_EC2_AMI_QUERY, "owner-id="+conf.getStringKey("imageOwner")+";state=available;image-type=machine");
+ } else if (groovyTruth(conf.getStringKey("anyOwner"))) {
+ // set `anyOwner: true` to override the default query (which is restricted to certain owners as per below),
+ // allowing the AMI query to bind to any machine
+ // (note however, we sometimes pick defaults in JcloudsLocationFactory);
+ // (and be careful, this can give a LOT of data back, taking several minutes,
+ // and requiring extra memory allocated on the command-line)
+ properties.setProperty(PROPERTY_EC2_AMI_QUERY, "state=available;image-type=machine");
+ /*
+ * by default the following filters are applied:
+ * Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&
+ * Filter.1.Value.2=063491364108&
+ * Filter.1.Value.3=099720109477&
+ * Filter.1.Value.4=411009282317&
+ * Filter.2.Name=state&Filter.2.Value.1=available&
+ * Filter.3.Name=image-type&Filter.3.Value.1=machine&
+ */
+ }
+
+ // occasionally can get com.google.common.util.concurrent.UncheckedExecutionException: java.lang.RuntimeException:
+ // security group eu-central-1/jclouds#brooklyn-bxza-alex-eu-central-shoul-u2jy-nginx-ielm is not available after creating
+ // the default timeout was 500ms so let's raise it in case that helps
+ properties.setProperty(EC2Constants.PROPERTY_EC2_TIMEOUT_SECURITYGROUP_PRESENT, ""+Duration.seconds(30).toMilliseconds());
+ }
+
+ // FIXME Deprecated mechanism, should have a ConfigKey for overrides
+ Map<String, Object> extra = Maps.filterKeys(conf.getAllConfig(), Predicates.containsPattern("^jclouds\\."));
+ if (extra.size() > 0) {
+ LOG.warn("Jclouds using deprecated property overrides: "+Sanitizer.sanitize(extra));
+ }
+ properties.putAll(extra);
+
+ String endpoint = conf.get(CloudLocationConfig.CLOUD_ENDPOINT);
+ if (!groovyTruth(endpoint)) endpoint = getDeprecatedProperty(conf, Constants.PROPERTY_ENDPOINT);
+ if (groovyTruth(endpoint)) properties.setProperty(Constants.PROPERTY_ENDPOINT, endpoint);
+
+ Map<?,?> cacheKey = MutableMap.builder()
+ .putAll(properties)
+ .put("provider", provider)
+ .put("identity", identity)
+ .put("credential", credential)
+ .putIfNotNull("endpoint", endpoint)
+ .build()
+ .asUnmodifiable();
+
+ if (allowReuse) {
+ ComputeService result = cachedComputeServices.get(cacheKey);
+ if (result!=null) {
+ LOG.trace("jclouds ComputeService cache hit for compute service, for "+Sanitizer.sanitize(properties));
+ return result;
+ }
+ LOG.debug("jclouds ComputeService cache miss for compute service, creating, for "+Sanitizer.sanitize(properties));
+ }
+
+ Iterable<Module> modules = getCommonModules();
+
+ // Synchronizing to avoid deadlock from sun.reflect.annotation.AnnotationType.
+ // See https://github.com/brooklyncentral/brooklyn/issues/974
+ ComputeServiceContext computeServiceContext;
+ synchronized (createComputeServicesMutex) {
+ computeServiceContext = ContextBuilder.newBuilder(provider)
+ .modules(modules)
+ .credentials(identity, credential)
+ .overrides(properties)
+ .build(ComputeServiceContext.class);
+ }
+ final ComputeService computeService = computeServiceContext.getComputeService();
+ if (allowReuse) {
+ synchronized (cachedComputeServices) {
+ ComputeService result = cachedComputeServices.get(cacheKey);
+ if (result != null) {
+ LOG.debug("jclouds ComputeService cache recovery for compute service, for "+Sanitizer.sanitize(cacheKey));
+ //keep the old one, discard the new one
+ computeService.getContext().close();
+ return result;
+ }
+ LOG.debug("jclouds ComputeService created "+computeService+", adding to cache, for "+Sanitizer.sanitize(properties));
+ cachedComputeServices.put(cacheKey, computeService);
+ }
+ }
+ return computeService;
+ }
+
+ /** returns the jclouds modules we typically install */
+ protected ImmutableSet<Module> getCommonModules() {
+ return ImmutableSet.<Module> of(
+ new SshjSshClientModule(),
+ new SLF4JLoggingModule(),
+ new BouncyCastleCryptoModule());
+ }
+
+ protected String getDeprecatedProperty(ConfigBag conf, String key) {
+ if (conf.containsKey(key)) {
+ LOG.warn("Jclouds using deprecated brooklyn-jclouds property "+key+": "+Sanitizer.sanitize(conf.getAllConfig()));
+ return (String) conf.getStringKey(key);
+ } else {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java
new file mode 100644
index 0000000..5aa026d
--- /dev/null
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.location.LocationRegistry;
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.brooklyn.location.LocationResolver;
+import org.apache.brooklyn.location.LocationSpec;
+import org.apache.brooklyn.location.NoMachinesAvailableException;
+import org.apache.brooklyn.location.basic.BasicLocationRegistry;
+import org.apache.brooklyn.location.basic.FixedListMachineProvisioningLocation;
+import org.apache.brooklyn.location.basic.LocationConfigKeys;
+import org.apache.brooklyn.location.basic.LocationConfigUtils;
+import org.apache.brooklyn.location.basic.LocationInternal;
+import org.apache.brooklyn.location.basic.LocationPropertiesFromBrooklynProperties;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.text.KeyValueParser;
+import brooklyn.util.text.Strings;
+import brooklyn.util.text.WildcardGlobs;
+import brooklyn.util.text.WildcardGlobs.PhraseTreatment;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * Examples of valid specs:
+ * <ul>
+ * <li>byon:(hosts=myhost)
+ * <li>byon:(hosts="myhost, myhost2")
+ * <li>byon:(hosts="myhost, myhost2", name="my location name")
+ * </ul>
+ *
+ * @author aled
+ */
+@SuppressWarnings({"unchecked","rawtypes"})
+public class JcloudsByonLocationResolver implements LocationResolver {
+
+ public static final Logger log = LoggerFactory.getLogger(JcloudsByonLocationResolver.class);
+
+ public static final String BYON = "jcloudsByon";
+
+ private static final Pattern PATTERN = Pattern.compile("("+BYON+"|"+BYON.toUpperCase()+")" + ":" + "\\((.*)\\)$");
+
+ private ManagementContext managementContext;
+
+ @Override
+ public void init(ManagementContext managementContext) {
+ this.managementContext = checkNotNull(managementContext, "managementContext");
+ }
+
+ // TODO Remove some duplication from JcloudsResolver; needs more careful review
+ @Override
+ public FixedListMachineProvisioningLocation<JcloudsSshMachineLocation> newLocationFromString(Map locationFlags, String spec, LocationRegistry registry) {
+ Map globalProperties = registry.getProperties();
+
+ Matcher matcher = PATTERN.matcher(spec);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Invalid location '"+spec+"'; must specify something like jcloudsByon(provider=\"aws-ec2\",region=\"us-east-1\",hosts=\"i-f2014593,i-d1234567\")");
+ }
+
+ String argsPart = matcher.group(2);
+ Map<String, String> argsMap = KeyValueParser.parseMap(argsPart);
+
+ // prefer args map over location flags
+
+ String namedLocation = (String) locationFlags.get(LocationInternal.NAMED_SPEC_NAME.getName());
+
+ String providerOrApi = argsMap.containsKey("provider") ? argsMap.get("provider") : (String)locationFlags.get("provider");
+
+ String regionName = argsMap.containsKey("region") ? argsMap.get("region") : (String)locationFlags.get("region");
+
+ String endpoint = argsMap.containsKey("endpoint") ? argsMap.get("endpoint") : (String)locationFlags.get("endpoint");
+
+ String name = argsMap.containsKey("name") ? argsMap.get("name") : (String)locationFlags.get("name");
+
+ String user = argsMap.containsKey("user") ? argsMap.get("user") : (String)locationFlags.get("user");
+
+ String privateKeyFile = argsMap.containsKey("privateKeyFile") ? argsMap.get("privateKeyFile") : (String)locationFlags.get("privateKeyFile");
+
+ String hosts = argsMap.get("hosts");
+
+ if (Strings.isEmpty(providerOrApi)) {
+ throw new IllegalArgumentException("Invalid location '"+spec+"'; provider must be defined");
+ }
+ if (hosts == null || hosts.isEmpty()) {
+ throw new IllegalArgumentException("Invalid location '"+spec+"'; at least one host must be defined");
+ }
+ if (argsMap.containsKey("name") && (Strings.isEmpty(name))) {
+ throw new IllegalArgumentException("Invalid location '"+spec+"'; if name supplied then value must be non-empty");
+ }
+
+ // For everything in brooklyn.properties, only use things with correct prefix (and remove that prefix).
+ // But for everything passed in via locationFlags, pass those as-is.
+ // TODO Should revisit the locationFlags: where are these actually used? Reason accepting properties without
+ // full prefix is that the map's context is explicitly this location, rather than being generic properties.
+ Map allProperties = getAllProperties(registry, globalProperties);
+ Map jcloudsProperties = new JcloudsPropertiesFromBrooklynProperties().getJcloudsProperties(providerOrApi, regionName, namedLocation, allProperties);
+ jcloudsProperties.putAll(locationFlags);
+ jcloudsProperties.putAll(argsMap);
+
+ String jcloudsSpec = "jclouds:"+providerOrApi + (regionName != null ? ":"+regionName : "") + (endpoint != null ? ":"+endpoint : "");
+ JcloudsLocation jcloudsLocation = (JcloudsLocation) registry.resolve(jcloudsSpec, jcloudsProperties);
+
+ List<String> hostIdentifiers = WildcardGlobs.getGlobsAfterBraceExpansion("{"+hosts+"}",
+ true /* numeric */, /* no quote support though */ PhraseTreatment.NOT_A_SPECIAL_CHAR, PhraseTreatment.NOT_A_SPECIAL_CHAR);
+ List<JcloudsSshMachineLocation> machines = Lists.newArrayList();
+
+ for (String hostIdentifier : hostIdentifiers) {
+ Map<?, ?> machineFlags = MutableMap.builder()
+ .put("id", hostIdentifier)
+ .putIfNotNull("user", user)
+ .putIfNotNull("privateKeyFile", privateKeyFile)
+ .build();
+ try {
+ JcloudsSshMachineLocation machine = jcloudsLocation.rebindMachine(jcloudsLocation.config().getBag().putAll(machineFlags));
+ machines.add(machine);
+ } catch (NoMachinesAvailableException e) {
+ log.warn("Error rebinding to jclouds machine "+hostIdentifier+" in "+jcloudsLocation, e);
+ Exceptions.propagate(e);
+ }
+ }
+
+ ConfigBag flags = ConfigBag.newInstance(jcloudsProperties);
+
+ flags.putStringKey("machines", machines);
+ flags.putIfNotNull(LocationConfigKeys.USER, user);
+ flags.putStringKeyIfNotNull("name", name);
+
+ if (registry != null)
+ LocationPropertiesFromBrooklynProperties.setLocalTempDir(registry.getProperties(), flags);
+
+ log.debug("Created Jclouds BYON location "+name+": "+machines);
+
+ return managementContext.getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class)
+ .configure(flags.getAllConfig())
+ .configure(LocationConfigUtils.finalAndOriginalSpecs(spec, locationFlags, globalProperties, namedLocation)));
+ }
+
+ private Map getAllProperties(LocationRegistry registry, Map<?,?> properties) {
+ Map<Object,Object> allProperties = Maps.newHashMap();
+ if (registry!=null) allProperties.putAll(registry.getProperties());
+ allProperties.putAll(properties);
+ return allProperties;
+ }
+
+ @Override
+ public String getPrefix() {
+ return BYON;
+ }
+
+ @Override
+ public boolean accepts(String spec, LocationRegistry registry) {
+ return BasicLocationRegistry.isResolverPrefixForSpec(this, spec, true);
+ }
+}
\ No newline at end of file