Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.core.config.ConfigBag;
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 com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
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 ConfigBag config;
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].*)?");
}
protected 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 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 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
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 += punishmentForOldOsVersions(img, OsFamily.CENTOS, 7);
score += 3;
}
else if (os.getFamily().equals(OsFamily.UBUNTU)) {
score += punishmentForOldOsVersions(img, OsFamily.UBUNTU, 12);
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().contains(os.getFamily().toString().toLowerCase()))
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;
if ("obsolete".equalsIgnoreCase(deprecated))
return -40;
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;
}
@Override
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();
}
}
protected void use(ConfigBag config) {
if (this.config !=null && !this.config.equals(config))
throw new IllegalStateException("ImageChooser must be cloned to set config");
this.config = config;
}
public BrooklynImageChooser cloneFor(ComputeService service) {
BrooklynImageChooser result = clone();
result.use(service);
return result;
}
public BrooklynImageChooser cloneFor(ConfigBag config) {
BrooklynImageChooser result = clone();
result.use(config);
return result;
}
public static class OrderingScoredWithoutDefaults extends Ordering implements ComputeServiceAwareChooser,
ConfigAwareChooser{
private BrooklynImageChooser chooser;
public OrderingScoredWithoutDefaults(BrooklynImageChooser chooser) {
this.chooser = chooser;
}
@Override
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));
}
@Override
public OrderingScoredWithoutDefaults cloneFor(ConfigBag config) {
return new OrderingScoredWithoutDefaults(chooser.cloneFor(config));
}
}
public Ordering orderingScoredWithoutDefaults() {
return new OrderingScoredWithoutDefaults(this);
}
/** @deprecated since 0.7.0 kept in case persisted */
@Deprecated
public Ordering orderingScoredWithoutDefaultsDeprecated() {
return new Ordering() {
@Override
public int compare(Image left, Image right) {
return BrooklynImageChooser.compare(score(left), score(right));
}
};
}
public static class OrderingWithDefaults extends Ordering implements ComputeServiceAwareChooser,
ConfigAwareChooser {
Ordering primaryOrdering;
public OrderingWithDefaults(final Ordering 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. natural().nullsFirst())
.compare(left.getVersion(), right.getVersion(), Ordering. natural().nullsFirst())
.compare(left.getDescription(), right.getDescription(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch(), Ordering. natural().nullsFirst()).result();
}
@Override
public OrderingWithDefaults cloneFor(ComputeService service) {
if (primaryOrdering instanceof ComputeServiceAwareChooser) {
return new OrderingWithDefaults( BrooklynImageChooser.cloneFor(primaryOrdering, service) );
}
return this;
}
@Override
public OrderingWithDefaults cloneFor(ConfigBag config) {
if (primaryOrdering instanceof ConfigAwareChooser) {
return new OrderingWithDefaults( BrooklynImageChooser.cloneFor(primaryOrdering, config) );
}
return this;
}
}
public static Ordering orderingWithDefaults(final Ordering primaryOrdering) {
return new OrderingWithDefaults(primaryOrdering);
}
/** @deprecated since 0.7.0 kept in case persisted */
@Deprecated
public static Ordering orderingWithDefaultsDeprecated(final Ordering primaryOrdering) {
return new Ordering() {
@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. natural().nullsFirst())
.compare(left.getVersion(), right.getVersion(), Ordering. natural().nullsFirst())
.compare(left.getDescription(), right.getDescription(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(), Ordering. natural().nullsFirst())
.compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch(), Ordering. natural().nullsFirst()).result();
}
};
}
public static class ImageChooserFromOrdering implements Function, Image>,
ComputeServiceAwareChooser, ConfigAwareChooser {
final List> orderings;
public ImageChooserFromOrdering(final Ordering ordering) {
this(ImmutableList.of(ordering));
}
public ImageChooserFromOrdering(Iterable extends Ordering super Image>> orderings) {
this.orderings = ImmutableList.copyOf(checkNotNull(orderings, "orderings"));
}
@Override
public Image apply(Iterable extends Image> input) {
List extends Image> maxImages = multiMax(Ordering.compound(orderings), input);
return maxImages.get(maxImages.size() - 1);
}
@Override
public ImageChooserFromOrdering cloneFor(ComputeService service) {
if (Iterables.tryFind(orderings, Predicates.instanceOf(ComputeServiceAwareChooser.class)).isPresent()) {
List> clonedOrderings = Lists.newArrayList();
for (Ordering super Image> ordering : orderings) {
if (ordering instanceof ComputeServiceAwareChooser) {
clonedOrderings.add(BrooklynImageChooser.cloneFor(ordering, service));
} else {
clonedOrderings.add(ordering);
}
}
return new ImageChooserFromOrdering(clonedOrderings);
} else {
return this;
}
}
@Override
public ImageChooserFromOrdering cloneFor(ConfigBag config) {
if (Iterables.tryFind(orderings, Predicates.instanceOf(ConfigAwareChooser.class)).isPresent()) {
List> clonedOrderings = Lists.newArrayList();
for (Ordering super Image> ordering : orderings) {
if (ordering instanceof ConfigAwareChooser) {
clonedOrderings.add(BrooklynImageChooser.cloneFor(ordering, config));
} else {
clonedOrderings.add(ordering);
}
}
return new ImageChooserFromOrdering(clonedOrderings);
} else {
return this;
}
}
@Override
public String toString(){
return getClass().getName();
}
}
public static Function, Image> imageChooserFromOrdering(final Ordering ordering) {
return new ImageChooserFromOrdering(ordering);
}
public static Function, Image> imageChooserFromOrderings(Iterable extends Ordering super Image>> orderings) {
return new ImageChooserFromOrdering(orderings);
}
/** @deprecated since 0.7.0 kept in case persisted */
@Deprecated
public static Function, Image> imageChooserFromOrderingDeprecated(final Ordering ordering) {
return new Function, 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 {
public T cloneFor(ComputeService service);
}
protected interface ConfigAwareChooser {
public T cloneFor(ConfigBag config);
}
/**
* Attempts to clone the given item for use with the given {@link ComputeService} and/or the
* given config, if the item is {@link ComputeServiceAwareChooser} or {@link ConfigAwareChooser};
* otherwise it returns the item unchanged.
*/
public static T cloneFor(T item, ComputeService service, ConfigBag config) {
T result = cloneFor(item, service);
return cloneFor(result, config);
}
/**
* 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 cloneFor(T item, ComputeService service) {
if (item instanceof ComputeServiceAwareChooser) {
return ((ComputeServiceAwareChooser)item).cloneFor(service);
}
return item;
}
/**
* Attempts to clone the given item for use with the given {@link ConfigBag}, if
* the item is {@link ConfigAwareChooser}; otherwise it returns the item unchanged.
*/
@SuppressWarnings("unchecked")
public static T cloneFor(T item, ConfigBag service) {
if (item instanceof ConfigAwareChooser) {
return ((ConfigAwareChooser)item).cloneFor(service);
}
return item;
}
// from jclouds
static List multiMax(Comparator ordering, Iterable iterable) {
Iterator iterator = iterable.iterator();
List 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 ordering() {
return orderingWithDefaults(orderingScoredWithoutDefaults());
}
public Function,Image> chooser() {
return imageChooserFromOrdering(ordering());
}
@Override
public String toString(){
return getClass().getName();
}
}