| /** |
| * Licensed to jclouds, Inc. (jclouds) under one or more |
| * contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. jclouds 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.jclouds.compute.domain.internal; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static com.google.common.base.Preconditions.checkState; |
| import static com.google.common.base.Predicates.and; |
| import static com.google.common.collect.Iterables.filter; |
| import static com.google.common.collect.Iterables.find; |
| import static com.google.common.collect.Iterables.size; |
| import static com.google.common.collect.Iterables.transform; |
| import static com.google.common.collect.Iterables.tryFind; |
| import static com.google.common.collect.Lists.newArrayList; |
| import static java.lang.String.format; |
| import static org.jclouds.compute.util.ComputeServiceUtils.getCores; |
| import static org.jclouds.compute.util.ComputeServiceUtils.getCoresAndSpeed; |
| import static org.jclouds.compute.util.ComputeServiceUtils.getSpace; |
| |
| import java.util.List; |
| import java.util.NoSuchElementException; |
| import java.util.Set; |
| import java.util.regex.Pattern; |
| |
| import javax.annotation.Resource; |
| import javax.inject.Inject; |
| import javax.inject.Named; |
| import javax.inject.Provider; |
| |
| import org.jclouds.collect.Memoized; |
| import org.jclouds.compute.domain.ComputeMetadata; |
| import org.jclouds.compute.domain.Hardware; |
| import org.jclouds.compute.domain.Image; |
| import org.jclouds.compute.domain.OperatingSystem; |
| import org.jclouds.compute.domain.OsFamily; |
| 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 org.jclouds.compute.reference.ComputeServiceConstants; |
| import org.jclouds.domain.Location; |
| import org.jclouds.logging.Logger; |
| import org.jclouds.util.Lists2; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Function; |
| import com.google.common.base.Objects; |
| import com.google.common.base.Objects.ToStringHelper; |
| import com.google.common.base.Predicate; |
| import com.google.common.base.Predicates; |
| import com.google.common.base.Supplier; |
| import com.google.common.collect.ComparisonChain; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Ordering; |
| import com.google.common.primitives.Doubles; |
| |
| /** |
| * |
| * @author Adrian Cole |
| */ |
| public class TemplateBuilderImpl implements TemplateBuilder { |
| @Resource |
| @Named(ComputeServiceConstants.COMPUTE_LOGGER) |
| protected Logger logger = Logger.NULL; |
| |
| protected final Supplier<Set<? extends Image>> images; |
| protected final Supplier<Set<? extends Hardware>> hardwares; |
| protected final Supplier<Set<? extends Location>> locations; |
| protected final Supplier<Location> defaultLocation; |
| protected final Provider<TemplateOptions> optionsProvider; |
| protected final Provider<TemplateBuilder> defaultTemplateProvider; |
| |
| @VisibleForTesting |
| protected Location location; |
| @VisibleForTesting |
| protected String imageId; |
| @VisibleForTesting |
| protected String hardwareId; |
| @VisibleForTesting |
| protected String hypervisor; |
| @VisibleForTesting |
| protected String imageVersion; |
| @VisibleForTesting |
| protected OsFamily osFamily; |
| @VisibleForTesting |
| protected String osVersion; |
| @VisibleForTesting |
| protected Boolean os64Bit; |
| @VisibleForTesting |
| protected String osName; |
| @VisibleForTesting |
| protected String osDescription; |
| @VisibleForTesting |
| protected String osArch; |
| @VisibleForTesting |
| protected String imageName; |
| @VisibleForTesting |
| protected String imageDescription; |
| @VisibleForTesting |
| protected Predicate<Image> imagePredicate; |
| @VisibleForTesting |
| protected double minCores; |
| @VisibleForTesting |
| protected int minRam; |
| @VisibleForTesting |
| protected double minDisk; |
| @VisibleForTesting |
| protected boolean biggest; |
| @VisibleForTesting |
| protected boolean fastest; |
| @VisibleForTesting |
| protected TemplateOptions options; |
| |
| @Inject |
| protected TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations, |
| @Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> hardwares, |
| Supplier<Location> defaultLocation2, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider, |
| @Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider) { |
| this.locations = locations; |
| this.images = images; |
| this.hardwares = hardwares; |
| this.defaultLocation = defaultLocation2; |
| this.optionsProvider = optionsProvider; |
| this.defaultTemplateProvider = defaultTemplateProvider; |
| } |
| |
| static Predicate<Hardware> supportsImagesPredicate(final Iterable<? extends Image> images) { |
| return new Predicate<Hardware>() { |
| @Override |
| public boolean apply(final Hardware hardware) { |
| return Iterables.any(images, new Predicate<Image>() { |
| |
| @Override |
| public boolean apply(Image input) { |
| return hardware.supportsImage().apply(input); |
| } |
| |
| @Override |
| public String toString() { |
| return "hardware(" + hardware + ").supportsImage()"; |
| } |
| |
| }); |
| |
| } |
| |
| }; |
| } |
| |
| final Predicate<ComputeMetadata> locationPredicate = new NullEqualToIsParentOrIsGrandparentOfCurrentLocation(new Supplier<Location>(){ |
| |
| @Override |
| public Location get() { |
| return location; |
| } |
| |
| }); |
| |
| private final Predicate<Image> idPredicate = new Predicate<Image>() { |
| @Override |
| public boolean apply(Image input) { |
| boolean returnVal = true; |
| if (imageId != null) { |
| returnVal = imageId.equals(input.getId()); |
| // match our input params so that the later predicates pass. |
| if (returnVal) { |
| fromImage(input); |
| } |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "imageId(" + imageId + ")"; |
| } |
| }; |
| |
| private final Predicate<OperatingSystem> osFamilyPredicate = new Predicate<OperatingSystem>() { |
| |
| @Override |
| public boolean apply(OperatingSystem input) { |
| boolean returnVal = true; |
| if (osFamily != null) |
| returnVal = osFamily.equals(input.getFamily()); |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "osFamily(" + osFamily + ")"; |
| } |
| }; |
| |
| private final Predicate<OperatingSystem> osNamePredicate = new Predicate<OperatingSystem>() { |
| @Override |
| public boolean apply(OperatingSystem input) { |
| boolean returnVal = true; |
| if (osName != null) { |
| if (input.getName() == null) |
| returnVal = false; |
| else |
| returnVal = input.getName().contains(osName) || input.getName().matches(osName); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "osName(" + osName + ")"; |
| } |
| }; |
| |
| private final Predicate<OperatingSystem> osDescriptionPredicate = new Predicate<OperatingSystem>() { |
| @Override |
| public boolean apply(OperatingSystem input) { |
| boolean returnVal = true; |
| if (osDescription != null) { |
| if (input.getDescription() == null) |
| returnVal = false; |
| else |
| returnVal = input.getDescription().contains(osDescription) |
| || input.getDescription().matches(osDescription); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "osDescription(" + osDescription + ")"; |
| } |
| }; |
| |
| private final Predicate<OperatingSystem> osVersionPredicate = new Predicate<OperatingSystem>() { |
| @Override |
| public boolean apply(OperatingSystem input) { |
| boolean returnVal = true; |
| if (osVersion != null) { |
| if (input.getVersion() == null) |
| returnVal = false; |
| else |
| returnVal = input.getVersion().contains(osVersion) || input.getVersion().matches(osVersion); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "osVersion(" + osVersion + ")"; |
| } |
| }; |
| |
| private final Predicate<OperatingSystem> os64BitPredicate = new Predicate<OperatingSystem>() { |
| @Override |
| public boolean apply(OperatingSystem input) { |
| boolean returnVal = true; |
| if (os64Bit != null) { |
| if (os64Bit) |
| return input.is64Bit(); |
| else |
| return !input.is64Bit(); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "os64Bit(" + os64Bit + ")"; |
| } |
| }; |
| |
| private final Predicate<OperatingSystem> osArchPredicate = new Predicate<OperatingSystem>() { |
| @Override |
| public boolean apply(OperatingSystem input) { |
| boolean returnVal = true; |
| if (osArch != null) { |
| if (input.getArch() == null) |
| returnVal = false; |
| else |
| returnVal = input.getArch().contains(osArch) || input.getArch().matches(osArch); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "osArch(" + osArch + ")"; |
| } |
| }; |
| |
| private final Predicate<Image> imageVersionPredicate = new Predicate<Image>() { |
| @Override |
| public boolean apply(Image input) { |
| boolean returnVal = true; |
| if (imageVersion != null) { |
| if (input.getVersion() == null) |
| returnVal = false; |
| else |
| returnVal = input.getVersion().contains(imageVersion) || input.getVersion().matches(imageVersion); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "imageVersion(" + imageVersion + ")"; |
| } |
| }; |
| |
| private final Predicate<Image> imageNamePredicate = new Predicate<Image>() { |
| @Override |
| public boolean apply(Image input) { |
| boolean returnVal = true; |
| if (imageName != null) { |
| if (input.getName() == null) |
| returnVal = false; |
| else |
| returnVal = input.getName().equals(imageName) || input.getName().contains(imageName) |
| || input.getName().matches(imageName); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "imageName(" + imageName + ")"; |
| } |
| }; |
| |
| private final Predicate<Image> imageDescriptionPredicate = new Predicate<Image>() { |
| @Override |
| public boolean apply(Image input) { |
| boolean returnVal = true; |
| if (imageDescription != null) { |
| if (input.getDescription() == null) |
| returnVal = false; |
| else |
| returnVal = input.getDescription().equals(imageDescription) |
| || input.getDescription().contains(imageDescription) |
| || input.getDescription().matches(imageDescription); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "imageDescription(" + imageDescription + ")"; |
| } |
| }; |
| |
| private final Predicate<Hardware> hardwareIdPredicate = new Predicate<Hardware>() { |
| @Override |
| public boolean apply(Hardware input) { |
| boolean returnVal = true; |
| if (hardwareId != null) { |
| returnVal = hardwareId.equals(input.getId()); |
| // match our input params so that the later predicates pass. |
| if (returnVal) { |
| fromHardware(input); |
| } |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "hardwareId(" + hardwareId + ")"; |
| } |
| }; |
| |
| private final Predicate<Hardware> hypervisorPredicate = new Predicate<Hardware>() { |
| @Override |
| public boolean apply(Hardware input) { |
| boolean returnVal = true; |
| if (hypervisor != null) { |
| if (input.getHypervisor() == null) |
| returnVal = false; |
| else |
| returnVal = input.getHypervisor().contains(hypervisor) |
| || input.getHypervisor().matches(hypervisor); |
| } |
| return returnVal; |
| } |
| |
| @Override |
| public String toString() { |
| return "hypervisorMatches(" + hypervisor + ")"; |
| } |
| }; |
| |
| private final Predicate<Hardware> hardwareCoresPredicate = new Predicate<Hardware>() { |
| @Override |
| public boolean apply(Hardware input) { |
| double cores = getCores(input); |
| return cores >= TemplateBuilderImpl.this.minCores; |
| } |
| |
| @Override |
| public String toString() { |
| return "minCores(" + minCores + ")"; |
| } |
| }; |
| |
| private final Predicate<Hardware> hardwareDiskPredicate = new Predicate<Hardware>() { |
| @Override |
| public boolean apply(Hardware input) { |
| return getSpace(input) >= TemplateBuilderImpl.this.minDisk; |
| } |
| |
| @Override |
| public String toString() { |
| return "minDisk(" + minDisk + ")"; |
| } |
| }; |
| |
| private final Predicate<Hardware> hardwareRamPredicate = new Predicate<Hardware>() { |
| @Override |
| public boolean apply(Hardware input) { |
| return input.getRam() >= TemplateBuilderImpl.this.minRam; |
| } |
| |
| @Override |
| public String toString() { |
| return "minRam(" + minRam + ")"; |
| } |
| }; |
| |
| private Predicate<Hardware> buildHardwarePredicate() { |
| List<Predicate<Hardware>> predicates = newArrayList(); |
| if (location != null) |
| predicates.add(new Predicate<Hardware>() { |
| |
| @Override |
| public boolean apply(Hardware input) { |
| return locationPredicate.apply(input); |
| } |
| |
| @Override |
| public String toString() { |
| return locationPredicate.toString(); |
| } |
| }); |
| if (hypervisor != null) |
| predicates.add(hypervisorPredicate); |
| predicates.add(hardwareCoresPredicate); |
| predicates.add(hardwareRamPredicate); |
| predicates.add(hardwareDiskPredicate); |
| |
| // looks verbose, but explicit <Hardware> type needed for this to compile |
| // properly |
| Predicate<Hardware> hardwarePredicate = predicates.size() == 1 ? Iterables.<Predicate<Hardware>> get(predicates, 0) |
| : Predicates.<Hardware> and(predicates); |
| return hardwarePredicate; |
| } |
| |
| static final Ordering<Hardware> DEFAULT_SIZE_ORDERING = new Ordering<Hardware>() { |
| public int compare(Hardware left, Hardware right) { |
| return ComparisonChain.start().compare(getCores(left), getCores(right)).compare(left.getRam(), right.getRam()) |
| .compare(getSpace(left), getSpace(right)).result(); |
| } |
| }; |
| static final Ordering<Hardware> BY_CORES_ORDERING = new Ordering<Hardware>() { |
| public int compare(Hardware left, Hardware right) { |
| return Doubles.compare(getCoresAndSpeed(left), getCoresAndSpeed(right)); |
| } |
| }; |
| static final Ordering<Image> DEFAULT_IMAGE_ORDERING = new Ordering<Image>() { |
| public int compare(Image left, Image right) { |
| return ComparisonChain.start() |
| .compare(left.getName(), right.getName(), Ordering.<String> natural().nullsLast()) |
| .compare(left.getVersion(), right.getVersion(), Ordering.<String> natural().nullsLast()) |
| .compare(left.getDescription(), right.getDescription(), Ordering.<String> natural().nullsLast()) |
| .compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(),// |
| Ordering.<String> natural().nullsLast()) |
| .compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(),// |
| Ordering.<String> natural().nullsLast()) |
| .compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(),// |
| Ordering.<String> natural().nullsLast()) |
| .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch(),// |
| Ordering.<String> natural().nullsLast()).result(); |
| } |
| }; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder fromTemplate(Template template) { |
| location = template.getLocation(); |
| fromHardware(template.getHardware()); |
| fromImage(template.getImage()); |
| options(template.getOptions()); |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder fromHardware(Hardware hardware) { |
| if (currentLocationWiderThan(hardware.getLocation())) |
| this.location = hardware.getLocation(); |
| this.minCores = getCores(hardware); |
| this.minRam = hardware.getRam(); |
| this.minDisk = getSpace(hardware); |
| this.hypervisor = hardware.getHypervisor(); |
| return this; |
| } |
| |
| private boolean currentLocationWiderThan(Location location) { |
| return this.location == null || (location != null && this.location.getScope().compareTo(location.getScope()) < 0); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder fromImage(Image image) { |
| if (currentLocationWiderThan(image.getLocation())) |
| this.location = image.getLocation(); |
| if (image.getOperatingSystem().getFamily() != null) |
| this.osFamily = image.getOperatingSystem().getFamily(); |
| if (image.getName() != null) |
| this.imageName = image.getName(); |
| if (image.getDescription() != null) |
| this.imageDescription = String.format("^%s$", Pattern.quote(image.getDescription())); |
| if (image.getOperatingSystem().getName() != null) |
| this.osName = image.getOperatingSystem().getName(); |
| if (image.getOperatingSystem().getDescription() != null) |
| this.osDescription = image.getOperatingSystem().getDescription(); |
| if (image.getVersion() != null) |
| this.imageVersion = String.format("^%s$", Pattern.quote(image.getVersion())); |
| if (image.getOperatingSystem().getVersion() != null) |
| this.osVersion = image.getOperatingSystem().getVersion(); |
| this.os64Bit = image.getOperatingSystem().is64Bit(); |
| if (image.getOperatingSystem().getArch() != null) |
| this.osArch = image.getOperatingSystem().getArch(); |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder smallest() { |
| this.biggest = false; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder biggest() { |
| this.biggest = true; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder fastest() { |
| this.fastest = true; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder locationId(final String locationId) { |
| Set<? extends Location> locations = this.locations.get(); |
| try { |
| this.location = find(locations, new Predicate<Location>() { |
| |
| @Override |
| public boolean apply(Location input) { |
| return input.getId().equals(locationId); |
| } |
| |
| @Override |
| public String toString() { |
| return "locationId(" + locationId + ")"; |
| } |
| |
| }); |
| } catch (NoSuchElementException e) { |
| throw new NoSuchElementException(format("location id %s not found in: %s", locationId, locations)); |
| } |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder osFamily(OsFamily os) { |
| this.osFamily = os; |
| return this; |
| } |
| |
| private static final Function<Image, String> imageToId = new Function<Image, String>() { |
| |
| @Override |
| public String apply(Image arg0) { |
| return arg0.getId(); |
| } |
| |
| }; |
| |
| |
| private static final Function<Hardware, String> hardwareToId = new Function<Hardware, String>() { |
| |
| @Override |
| public String apply(Hardware arg0) { |
| return arg0.getId(); |
| } |
| |
| }; |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Template build() { |
| if (nothingChangedExceptOptions()) { |
| TemplateBuilder defaultTemplate = defaultTemplateProvider.get(); |
| if (options != null) |
| defaultTemplate.options(options); |
| return defaultTemplate.build(); |
| } |
| |
| if (options == null) |
| options = optionsProvider.get(); |
| logger.debug(">> searching params(%s)", this); |
| Set<? extends Image> images = getImages(); |
| checkState(images.size() > 0, "no images present!"); |
| Set<? extends Hardware> hardwaresToSearch = hardwares.get(); |
| checkState(hardwaresToSearch.size() > 0, "no hardware profiles present!"); |
| |
| Image image = null; |
| if (imageId != null) { |
| image = findImageWithId(images); |
| if (currentLocationWiderThan(image.getLocation())) |
| this.location = image.getLocation(); |
| } |
| |
| Hardware hardware = null; |
| if (hardwareId != null) { |
| hardware = findHardwareWithId(hardwaresToSearch); |
| if (currentLocationWiderThan(hardware.getLocation())) |
| this.location = hardware.getLocation(); |
| } |
| |
| // if the user hasn't specified a location id, or an image or hardware |
| // with location, let's search scoped to the implicit one |
| if (location == null) |
| location = defaultLocation.get(); |
| |
| if (image == null) { |
| Iterable<? extends Image> supportedImages = findSupportedImages(images); |
| if (hardware == null) |
| hardware = resolveHardware(hardwaresToSearch, supportedImages); |
| image = resolveImage(hardware, supportedImages); |
| } else { |
| if (hardware == null) |
| hardware = resolveHardware(hardwaresToSearch, ImmutableSet.of(image)); |
| } |
| |
| logger.debug("<< matched image(%s) hardware(%s) location(%s)", image.getId(), hardware.getId(), |
| location.getId()); |
| return new TemplateImpl(image, hardware, location, options); |
| } |
| |
| private Iterable<? extends Image> findSupportedImages(Set<? extends Image> images) { |
| Predicate<Image> imagePredicate = buildImagePredicate(); |
| Iterable<? extends Image> supportedImages = filter(images, imagePredicate); |
| if (size(supportedImages) == 0) { |
| throw throwNoSuchElementExceptionAfterLoggingImageIds( |
| format("no image matched predicate: %s", imagePredicate), images); |
| } |
| return supportedImages; |
| } |
| |
| private Image findImageWithId(Set<? extends Image> images) { |
| Image image; |
| // TODO: switch to GetImageStrategy in version 1.5 |
| image = tryFind(images, idPredicate).orNull(); |
| if (image == null) |
| throwNoSuchElementExceptionAfterLoggingImageIds(format("%s not found", idPredicate), images); |
| return image; |
| } |
| |
| private Hardware findHardwareWithId(Set<? extends Hardware> hardwaresToSearch) { |
| Hardware hardware; |
| // TODO: switch to GetHardwareStrategy in version 1.5 |
| hardware = tryFind(hardwaresToSearch, hardwareIdPredicate).orNull(); |
| if (hardware == null) |
| throw throwNoSuchElementExceptionAfterLoggingHardwareIds(format("%s not found", hardwareIdPredicate), |
| hardwaresToSearch); |
| return hardware; |
| } |
| |
| protected NoSuchElementException throwNoSuchElementExceptionAfterLoggingImageIds(String message, Iterable<? extends Image> images) { |
| NoSuchElementException exception = new NoSuchElementException(message); |
| if (logger.isTraceEnabled()) |
| logger.warn(exception, "image ids that didn't match: %s", transform(images, imageToId)); |
| throw exception; |
| } |
| |
| protected NoSuchElementException throwNoSuchElementExceptionAfterLoggingHardwareIds(String message, Iterable<? extends Hardware> hardwares) { |
| NoSuchElementException exception = new NoSuchElementException(message); |
| if (logger.isTraceEnabled()) |
| logger.warn(exception, "hardware ids that didn't match: %s", transform(hardwares, hardwareToId)); |
| throw exception; |
| } |
| |
| protected Hardware resolveHardware(Set<? extends Hardware> hardwarel, final Iterable<? extends Image> images) { |
| Ordering<Hardware> hardwareOrdering = hardwareSorter(); |
| |
| Iterable<Predicate<Image>> supportsImagePredicates = Iterables.transform(hardwarel, |
| new Function<Hardware, Predicate<Image>>() { |
| |
| @Override |
| public Predicate<Image> apply(Hardware input) { |
| return input.supportsImage(); |
| } |
| |
| }); |
| |
| Predicate<Image> supportsImagePredicate = Iterables.size(supportsImagePredicates) == 1 ? Iterables |
| .getOnlyElement(supportsImagePredicates) : Predicates.<Image>or(supportsImagePredicates); |
| |
| if (!Iterables.any(images, supportsImagePredicate)) { |
| String message = format("no hardware profiles support images matching params: %s", supportsImagePredicate); |
| throw throwNoSuchElementExceptionAfterLoggingHardwareIds(message, hardwarel); |
| } |
| |
| Iterable<? extends Hardware> hardwareCompatibleWithOurImages = filter(hardwarel, supportsImagesPredicate(images)); |
| Predicate<Hardware> hardwarePredicate = buildHardwarePredicate(); |
| Hardware hardware; |
| try { |
| hardware = hardwareOrdering.max(filter(hardwareCompatibleWithOurImages, hardwarePredicate)); |
| } catch (NoSuchElementException exception) { |
| String message = format("no hardware profiles match params: %s", hardwarePredicate); |
| throw throwNoSuchElementExceptionAfterLoggingHardwareIds(message, hardwareCompatibleWithOurImages); |
| } |
| logger.trace("<< matched hardware(%s)", hardware.getId()); |
| return hardware; |
| } |
| |
| protected Ordering<Hardware> hardwareSorter() { |
| Ordering<Hardware> hardwareOrdering = DEFAULT_SIZE_ORDERING; |
| if (!biggest) |
| hardwareOrdering = hardwareOrdering.reverse(); |
| if (fastest) |
| hardwareOrdering = Ordering.compound(ImmutableList.of(BY_CORES_ORDERING, hardwareOrdering)); |
| return hardwareOrdering; |
| } |
| |
| /** |
| * |
| * @param hardware |
| * @param supportedImages |
| * @throws NoSuchElementException |
| * if there's no image that matches the predicate |
| */ |
| protected Image resolveImage(final Hardware hardware, Iterable<? extends Image> supportedImages) { |
| Predicate<Image> imagePredicate = new Predicate<Image>() { |
| |
| @Override |
| public boolean apply(Image arg0) { |
| return hardware.supportsImage().apply(arg0); |
| } |
| |
| @Override |
| public String toString() { |
| return "hardware(" + hardware + ").supportsImage()"; |
| } |
| }; |
| |
| try { |
| Iterable<? extends Image> matchingImages = filter(supportedImages, imagePredicate); |
| if (logger.isTraceEnabled()) |
| logger.trace("<< matched images(%s)", transform(matchingImages, imageToId)); |
| List<? extends Image> maxImages = Lists2.multiMax(DEFAULT_IMAGE_ORDERING, matchingImages); |
| if (logger.isTraceEnabled()) |
| logger.trace("<< best images(%s)", transform(maxImages, imageToId)); |
| return maxImages.get(maxImages.size() - 1); |
| } catch (NoSuchElementException exception) { |
| throwNoSuchElementExceptionAfterLoggingImageIds(format("no image matched params: %s", toString()), |
| supportedImages); |
| assert false; |
| return null; |
| } |
| } |
| |
| protected Set<? extends Image> getImages() { |
| return images.get(); |
| } |
| |
| private Predicate<Image> buildImagePredicate() { |
| List<Predicate<Image>> predicates = newArrayList(); |
| if (location != null) |
| predicates.add(new Predicate<Image>() { |
| |
| @Override |
| public boolean apply(Image input) { |
| return locationPredicate.apply(input); |
| } |
| |
| @Override |
| public String toString() { |
| return locationPredicate.toString(); |
| } |
| }); |
| |
| final List<Predicate<OperatingSystem>> osPredicates = newArrayList(); |
| if (osFamily != null) |
| osPredicates.add(osFamilyPredicate); |
| if (osName != null) |
| osPredicates.add(osNamePredicate); |
| if (osDescription != null) |
| osPredicates.add(osDescriptionPredicate); |
| if (osVersion != null) |
| osPredicates.add(osVersionPredicate); |
| if (os64Bit != null) |
| osPredicates.add(os64BitPredicate); |
| if (osArch != null) |
| osPredicates.add(osArchPredicate); |
| if (osPredicates.size() > 0) |
| predicates.add(new Predicate<Image>() { |
| |
| @Override |
| public boolean apply(Image input) { |
| return and(osPredicates).apply(input.getOperatingSystem()); |
| } |
| |
| @Override |
| public String toString() { |
| return and(osPredicates).toString(); |
| } |
| |
| }); |
| if (imageVersion != null) |
| predicates.add(imageVersionPredicate); |
| if (imageName != null) |
| predicates.add(imageNamePredicate); |
| if (imageDescription != null) |
| predicates.add(imageDescriptionPredicate); |
| if (imagePredicate != null) |
| predicates.add(imagePredicate); |
| |
| // looks verbose, but explicit <Image> type needed for this to compile |
| // properly |
| Predicate<Image> imagePredicate = predicates.size() == 1 ? Iterables.<Predicate<Image>> get(predicates, 0) |
| : Predicates.<Image> and(predicates); |
| return imagePredicate; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder imageId(String imageId) { |
| this.imageId = imageId; |
| this.imageName = null; |
| this.imageDescription = null; |
| this.imagePredicate = null; |
| this.imageVersion = null; |
| this.osFamily = null; |
| this.osName = null; |
| this.osDescription = null; |
| this.osVersion = null; |
| this.os64Bit = null; |
| this.osArch = null; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder imageNameMatches(String nameRegex) { |
| this.imageName = nameRegex; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder imageDescriptionMatches(String descriptionRegex) { |
| this.imageDescription = descriptionRegex; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder imageMatches(Predicate<Image> condition) { |
| this.imagePredicate = condition; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder imageVersionMatches(String imageVersionRegex) { |
| this.imageVersion = imageVersionRegex; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder osVersionMatches(String osVersionRegex) { |
| this.osVersion = osVersionRegex; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder osArchMatches(String osArchitectureRegex) { |
| this.osArch = osArchitectureRegex; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder minCores(double minCores) { |
| this.minCores = minCores; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder minRam(int megabytes) { |
| this.minRam = megabytes; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder minDisk(double gigabytes) { |
| this.minDisk = gigabytes; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder osNameMatches(String osNameRegex) { |
| this.osName = osNameRegex; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder osDescriptionMatches(String osDescriptionRegex) { |
| this.osDescription = osDescriptionRegex; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder hardwareId(String hardwareId) { |
| this.hardwareId = hardwareId; |
| this.hypervisor = null; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder hypervisorMatches(String hypervisor) { |
| this.hypervisor = hypervisor; |
| return this; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder options(TemplateOptions options) { |
| this.options = optionsProvider.get(); |
| checkNotNull(options, "options").copyTo(this.options); |
| return this; |
| } |
| |
| @VisibleForTesting |
| boolean nothingChangedExceptOptions() { |
| return osFamily == null && location == null && imageId == null && hardwareId == null && hypervisor == null |
| && osName == null && imagePredicate == null && osDescription == null && imageVersion == null |
| && osVersion == null && osArch == null && os64Bit == null && imageName == null && imageDescription == null |
| && minCores == 0 && minRam == 0 && minDisk == 0 && !biggest && !fastest; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TemplateBuilder any() { |
| return defaultTemplateProvider.get(); |
| } |
| |
| @Override |
| public String toString() { |
| return string().toString(); |
| } |
| |
| /** |
| * @since 1.5 |
| */ |
| protected ToStringHelper string() { |
| ToStringHelper toString = Objects.toStringHelper("").omitNullValues(); |
| if (biggest) |
| toString.add("biggest", biggest); |
| if (fastest) |
| toString.add("fastest", fastest); |
| toString.add("imageName", imageName); |
| toString.add("imageDescription", imageDescription); |
| toString.add("imageId", imageId); |
| toString.add("imagePredicate", imagePredicate); |
| toString.add("imageVersion", imageVersion); |
| if (location != null) |
| toString.add("locationId", location.getId()); |
| if (minCores >0) //TODO: make non-primitive |
| toString.add("minCores", minCores); |
| if (minRam >0) //TODO: make non-primitive |
| toString.add("minRam", minRam); |
| if (minRam >0) //TODO: make non-primitive |
| toString.add("minRam", minRam); |
| if (minDisk >0) //TODO: make non-primitive |
| toString.add("minDisk", minDisk); |
| toString.add("osFamily", osFamily); |
| toString.add("osName", osName); |
| toString.add("osDescription", osDescription); |
| toString.add("osVersion", osVersion); |
| toString.add("osArch", osArch); |
| toString.add("os64Bit", os64Bit); |
| toString.add("hardwareId", hardwareId); |
| toString.add("hypervisor", hypervisor); |
| return toString; |
| } |
| |
| @Override |
| public TemplateBuilder os64Bit(boolean is64Bit) { |
| this.os64Bit = is64Bit; |
| return this; |
| } |
| |
| @Override |
| public TemplateBuilder from(TemplateBuilderSpec spec) { |
| return spec.copyTo(this, options != null ? options : optionsProvider.get()); |
| } |
| |
| @Override |
| public TemplateBuilder from(String spec) { |
| return from(TemplateBuilderSpec.parse(spec)); |
| } |
| |
| } |