1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.compute.domain.internal;
20
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.base.Predicates.and;
23 import static com.google.common.collect.Iterables.filter;
24 import static com.google.common.collect.Iterables.find;
25 import static com.google.common.collect.Iterables.size;
26 import static com.google.common.collect.Iterables.transform;
27 import static com.google.common.collect.Lists.newArrayList;
28 import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
29 import static org.jclouds.compute.util.ComputeServiceUtils.getCoresAndSpeed;
30 import static org.jclouds.compute.util.ComputeServiceUtils.getSpace;
31 import static java.lang.String.format;
32 import java.util.List;
33 import java.util.NoSuchElementException;
34 import java.util.Set;
35
36 import javax.annotation.Resource;
37 import javax.inject.Inject;
38 import javax.inject.Named;
39 import javax.inject.Provider;
40
41 import org.jclouds.collect.Memoized;
42 import org.jclouds.compute.domain.ComputeMetadata;
43 import org.jclouds.compute.domain.Hardware;
44 import org.jclouds.compute.domain.Image;
45 import org.jclouds.compute.domain.OperatingSystem;
46 import org.jclouds.compute.domain.OsFamily;
47 import org.jclouds.compute.domain.Template;
48 import org.jclouds.compute.domain.TemplateBuilder;
49 import org.jclouds.compute.options.TemplateOptions;
50 import org.jclouds.compute.reference.ComputeServiceConstants;
51 import org.jclouds.domain.Location;
52 import org.jclouds.logging.Logger;
53 import org.jclouds.util.Lists2;
54
55 import com.google.common.annotations.VisibleForTesting;
56 import com.google.common.base.Function;
57 import com.google.common.base.Predicate;
58 import com.google.common.base.Predicates;
59 import com.google.common.base.Supplier;
60 import com.google.common.collect.ComparisonChain;
61 import com.google.common.collect.ImmutableList;
62 import com.google.common.collect.Iterables;
63 import com.google.common.collect.Ordering;
64 import com.google.common.primitives.Doubles;
65
66
67
68
69
70 @SuppressWarnings("unchecked")
71 public class TemplateBuilderImpl implements TemplateBuilder {
72
73 @Resource
74 @Named(ComputeServiceConstants.COMPUTE_LOGGER)
75 protected Logger logger = Logger.NULL;
76
77 protected final Supplier<Set<? extends Image>> images;
78 protected final Supplier<Set<? extends Hardware>> hardwares;
79 protected final Supplier<Set<? extends Location>> locations;
80 protected final Supplier<Location> defaultLocation;
81 protected final Provider<TemplateOptions> optionsProvider;
82 protected final Provider<TemplateBuilder> defaultTemplateProvider;
83
84 @VisibleForTesting
85 protected Location location;
86 @VisibleForTesting
87 protected String imageId;
88 @VisibleForTesting
89 protected String hardwareId;
90 @VisibleForTesting
91 protected String imageVersion;
92 @VisibleForTesting
93 protected OsFamily osFamily;
94 @VisibleForTesting
95 protected String osVersion;
96 @VisibleForTesting
97 protected Boolean os64Bit;
98 @VisibleForTesting
99 protected String osName;
100 @VisibleForTesting
101 protected String osDescription;
102 @VisibleForTesting
103 protected String osArch;
104 @VisibleForTesting
105 protected String imageName;
106 @VisibleForTesting
107 protected String imageDescription;
108 @VisibleForTesting
109 protected Predicate<Image> imagePredicate;
110 @VisibleForTesting
111 protected double minCores;
112 @VisibleForTesting
113 protected int minRam;
114 @VisibleForTesting
115 protected boolean biggest;
116 @VisibleForTesting
117 protected boolean fastest;
118 @VisibleForTesting
119 protected TemplateOptions options;
120
121 @Inject
122 protected TemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
123 @Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> hardwares,
124 Supplier<Location> defaultLocation2, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
125 @Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider) {
126 this.locations = locations;
127 this.images = images;
128 this.hardwares = hardwares;
129 this.defaultLocation = defaultLocation2;
130 this.optionsProvider = optionsProvider;
131 this.defaultTemplateProvider = defaultTemplateProvider;
132 }
133
134
135
136
137
138
139
140
141 private final Predicate<ComputeMetadata> locationPredicate = new Predicate<ComputeMetadata>() {
142 @Override
143 public boolean apply(ComputeMetadata input) {
144 boolean returnVal = true;
145 if (location != null && input.getLocation() != null)
146 returnVal = location.equals(input.getLocation()) || location.getParent() != null
147 && location.getParent().equals(input.getLocation()) || location.getParent().getParent() != null
148 && location.getParent().getParent().equals(input.getLocation());
149 return returnVal;
150 }
151
152 @Override
153 public String toString() {
154 return location == null ? "anyLocation()" : "locationEqualsOrChildOf(" + location.getId() + ")";
155 }
156 };
157
158 private final Predicate<Image> idPredicate = new Predicate<Image>() {
159 @Override
160 public boolean apply(Image input) {
161 boolean returnVal = true;
162 if (imageId != null) {
163 returnVal = imageId.equals(input.getId());
164
165 if (returnVal) {
166 fromImage(input);
167 }
168 }
169 return returnVal;
170 }
171
172 @Override
173 public String toString() {
174 return "imageId(" + imageId + ")";
175 }
176 };
177
178 private final Predicate<OperatingSystem> osFamilyPredicate = new Predicate<OperatingSystem>() {
179
180 @Override
181 public boolean apply(OperatingSystem input) {
182 boolean returnVal = true;
183 if (osFamily != null)
184 returnVal = osFamily.equals(input.getFamily());
185 return returnVal;
186 }
187
188 @Override
189 public String toString() {
190 return "osFamily(" + osFamily + ")";
191 }
192 };
193
194 private final Predicate<OperatingSystem> osNamePredicate = new Predicate<OperatingSystem>() {
195 @Override
196 public boolean apply(OperatingSystem input) {
197 boolean returnVal = true;
198 if (osName != null) {
199 if (input.getName() == null)
200 returnVal = false;
201 else
202 returnVal = input.getName().contains(osName) || input.getName().matches(osName);
203 }
204 return returnVal;
205 }
206
207 @Override
208 public String toString() {
209 return "osName(" + osName + ")";
210 }
211 };
212
213 private final Predicate<OperatingSystem> osDescriptionPredicate = new Predicate<OperatingSystem>() {
214 @Override
215 public boolean apply(OperatingSystem input) {
216 boolean returnVal = true;
217 if (osDescription != null) {
218 if (input.getDescription() == null)
219 returnVal = false;
220 else
221 returnVal = input.getDescription().contains(osDescription)
222 || input.getDescription().matches(osDescription);
223 }
224 return returnVal;
225 }
226
227 @Override
228 public String toString() {
229 return "osDescription(" + osDescription + ")";
230 }
231 };
232
233 private final Predicate<OperatingSystem> osVersionPredicate = new Predicate<OperatingSystem>() {
234 @Override
235 public boolean apply(OperatingSystem input) {
236 boolean returnVal = true;
237 if (osVersion != null) {
238 if (input.getVersion() == null)
239 returnVal = false;
240 else
241 returnVal = input.getVersion().contains(osVersion) || input.getVersion().matches(osVersion);
242 }
243 return returnVal;
244 }
245
246 @Override
247 public String toString() {
248 return "osVersion(" + osVersion + ")";
249 }
250 };
251
252 private final Predicate<OperatingSystem> os64BitPredicate = new Predicate<OperatingSystem>() {
253 @Override
254 public boolean apply(OperatingSystem input) {
255 boolean returnVal = true;
256 if (os64Bit != null) {
257 if (os64Bit)
258 return input.is64Bit();
259 else
260 return !input.is64Bit();
261 }
262 return returnVal;
263 }
264
265 @Override
266 public String toString() {
267 return "os64Bit(" + os64Bit + ")";
268 }
269 };
270
271 private final Predicate<OperatingSystem> osArchPredicate = new Predicate<OperatingSystem>() {
272 @Override
273 public boolean apply(OperatingSystem input) {
274 boolean returnVal = true;
275 if (osArch != null) {
276 if (input.getArch() == null)
277 returnVal = false;
278 else
279 returnVal = input.getArch().contains(osArch) || input.getArch().matches(osArch);
280 }
281 return returnVal;
282 }
283
284 @Override
285 public String toString() {
286 return "osArch(" + osArch + ")";
287 }
288 };
289
290 private final Predicate<Image> imageVersionPredicate = new Predicate<Image>() {
291 @Override
292 public boolean apply(Image input) {
293 boolean returnVal = true;
294 if (imageVersion != null) {
295 if (input.getVersion() == null)
296 returnVal = false;
297 else
298 returnVal = input.getVersion().contains(imageVersion) || input.getVersion().matches(imageVersion);
299 }
300 return returnVal;
301 }
302
303 @Override
304 public String toString() {
305 return "imageVersion(" + imageVersion + ")";
306 }
307 };
308
309 private final Predicate<Image> imageNamePredicate = new Predicate<Image>() {
310 @Override
311 public boolean apply(Image input) {
312 boolean returnVal = true;
313 if (imageName != null) {
314 if (input.getName() == null)
315 returnVal = false;
316 else
317 returnVal = input.getName().contains(imageName) || input.getName().matches(imageName);
318 }
319 return returnVal;
320 }
321
322 @Override
323 public String toString() {
324 return "imageName(" + imageName + ")";
325 }
326 };
327 private final Predicate<Image> imageDescriptionPredicate = new Predicate<Image>() {
328 @Override
329 public boolean apply(Image input) {
330 boolean returnVal = true;
331 if (imageDescription != null) {
332 if (input.getDescription() == null)
333 returnVal = false;
334 else
335 returnVal = input.getDescription().equals(imageDescription)
336 || input.getDescription().contains(imageDescription)
337 || input.getDescription().matches(imageDescription);
338 }
339 return returnVal;
340 }
341
342 @Override
343 public String toString() {
344 return "imageDescription(" + imageDescription + ")";
345 }
346 };
347 private final Predicate<Hardware> hardwareIdPredicate = new Predicate<Hardware>() {
348 @Override
349 public boolean apply(Hardware input) {
350 boolean returnVal = true;
351 if (hardwareId != null) {
352 returnVal = hardwareId.equals(input.getId());
353
354 if (returnVal) {
355 fromHardware(input);
356 }
357 }
358 return returnVal;
359 }
360
361 @Override
362 public String toString() {
363 return "hardwareId(" + hardwareId + ")";
364 }
365 };
366
367 private final Predicate<Hardware> hardwareCoresPredicate = new Predicate<Hardware>() {
368 @Override
369 public boolean apply(Hardware input) {
370 double cores = getCores(input);
371 return cores >= TemplateBuilderImpl.this.minCores;
372 }
373
374 @Override
375 public String toString() {
376 return "minCores(" + minCores + ")";
377 }
378 };
379
380 private final Predicate<Hardware> hardwareRamPredicate = new Predicate<Hardware>() {
381 @Override
382 public boolean apply(Hardware input) {
383 return input.getRam() >= TemplateBuilderImpl.this.minRam;
384 }
385
386 @Override
387 public String toString() {
388 return "minRam(" + minRam + ")";
389 }
390 };
391 private final Predicate<Hardware> hardwarePredicate = and(hardwareIdPredicate, locationPredicate,
392 hardwareCoresPredicate, hardwareRamPredicate);
393
394 static final Ordering<Hardware> DEFAULT_SIZE_ORDERING = new Ordering<Hardware>() {
395 public int compare(Hardware left, Hardware right) {
396 return ComparisonChain.start().compare(getCores(left), getCores(right)).compare(left.getRam(), right.getRam())
397 .compare(getSpace(left), getSpace(right)).result();
398 }
399 };
400 static final Ordering<Hardware> BY_CORES_ORDERING = new Ordering<Hardware>() {
401 public int compare(Hardware left, Hardware right) {
402 return Doubles.compare(getCoresAndSpeed(left), getCoresAndSpeed(right));
403 }
404 };
405 static final Ordering<Image> DEFAULT_IMAGE_ORDERING = new Ordering<Image>() {
406 public int compare(Image left, Image right) {
407 return ComparisonChain.start()
408 .compare(left.getName(), right.getName(), Ordering.<String> natural().nullsLast())
409 .compare(left.getVersion(), right.getVersion(), Ordering.<String> natural().nullsLast())
410 .compare(left.getOperatingSystem().getName(), right.getOperatingSystem().getName(),
411 Ordering.<String> natural().nullsLast())
412 .compare(left.getOperatingSystem().getVersion(), right.getOperatingSystem().getVersion(),
413 Ordering.<String> natural().nullsLast())
414 .compare(left.getOperatingSystem().getDescription(), right.getOperatingSystem().getDescription(),
415 Ordering.<String> natural().nullsLast())
416 .compare(left.getOperatingSystem().getArch(), right.getOperatingSystem().getArch()).result();
417 }
418 };
419
420
421
422
423 @Override
424 public TemplateBuilder fromTemplate(Template template) {
425 location = template.getLocation();
426 fromHardware(template.getHardware());
427 fromImage(template.getImage());
428 options(template.getOptions());
429 return this;
430 }
431
432
433
434
435 @Override
436 public TemplateBuilder fromHardware(Hardware hardware) {
437 if (currentLocationWiderThan(hardware.getLocation()))
438 this.location = hardware.getLocation();
439 this.minCores = getCores(hardware);
440 this.minRam = hardware.getRam();
441 return this;
442 }
443
444 private boolean currentLocationWiderThan(Location location) {
445 return this.location == null || (location != null && this.location.getScope().compareTo(location.getScope()) < 0);
446 }
447
448
449
450
451 @Override
452 public TemplateBuilder fromImage(Image image) {
453 if (currentLocationWiderThan(image.getLocation()))
454 this.location = image.getLocation();
455 if (image.getOperatingSystem().getFamily() != null)
456 this.osFamily = image.getOperatingSystem().getFamily();
457 if (image.getName() != null)
458 this.imageName = image.getName();
459 if (image.getDescription() != null)
460 this.imageDescription = image.getDescription();
461 if (image.getOperatingSystem().getName() != null)
462 this.osName = image.getOperatingSystem().getName();
463 if (image.getOperatingSystem().getDescription() != null)
464 this.osDescription = image.getOperatingSystem().getDescription();
465 if (image.getVersion() != null)
466 this.imageVersion = image.getVersion();
467 if (image.getOperatingSystem().getVersion() != null)
468 this.osVersion = image.getOperatingSystem().getVersion();
469 this.os64Bit = image.getOperatingSystem().is64Bit();
470 if (image.getOperatingSystem().getArch() != null)
471 this.osArch = image.getOperatingSystem().getArch();
472 return this;
473 }
474
475
476
477
478 @Override
479 public TemplateBuilder smallest() {
480 this.biggest = false;
481 return this;
482 }
483
484
485
486
487 @Override
488 public TemplateBuilder biggest() {
489 this.biggest = true;
490 return this;
491 }
492
493
494
495
496 @Override
497 public TemplateBuilder fastest() {
498 this.fastest = true;
499 return this;
500 }
501
502
503
504
505 @Override
506 public TemplateBuilder locationId(final String locationId) {
507 Set<? extends Location> locations = this.locations.get();
508 try {
509 this.location = find(locations, new Predicate<Location>() {
510
511 @Override
512 public boolean apply(Location input) {
513 return input.getId().equals(locationId);
514 }
515
516 @Override
517 public String toString() {
518 return "locationId(" + locationId + ")";
519 }
520
521 });
522 } catch (NoSuchElementException e) {
523 throw new NoSuchElementException(format("location id %s not found in: %s", locationId, locations));
524 }
525 return this;
526 }
527
528
529
530
531 @Override
532 public TemplateBuilder osFamily(OsFamily os) {
533 this.osFamily = os;
534 return this;
535 }
536
537 private static final Function<Image, String> imageToId = new Function<Image, String>() {
538
539 @Override
540 public String apply(Image arg0) {
541 return arg0.getId();
542 }
543
544 };
545
546
547
548
549 @Override
550 public Template build() {
551 if (nothingChangedExceptOptions()) {
552 TemplateBuilder defaultTemplate = defaultTemplateProvider.get();
553 if (options != null)
554 defaultTemplate.options(options);
555 return defaultTemplate.build();
556 }
557 if (location == null)
558 location = defaultLocation.get();
559 if (options == null)
560 options = optionsProvider.get();
561 logger.debug(">> searching params(%s)", this);
562 Set<? extends Image> images = getImages();
563 Predicate<Image> imagePredicate = buildImagePredicate();
564 Iterable<? extends Image> supportedImages = filter(images, buildImagePredicate());
565 if (size(supportedImages) == 0) {
566 if (imagePredicate == idPredicate) {
567 throw new NoSuchElementException(format("%s not found", idPredicate));
568 } else {
569 throwNoSuchElementExceptionAfterLoggingImageIds(format("no image matched predicate: %s", imagePredicate),
570 images);
571 }
572 }
573 Hardware hardware = resolveSize(hardwareSorter(), supportedImages);
574 Image image = resolveImage(hardware, supportedImages);
575 logger.debug("<< matched image(%s)", image.getId());
576
577 return new TemplateImpl(image, hardware, location, options);
578 }
579
580 protected void throwNoSuchElementExceptionAfterLoggingImageIds(String message, Iterable<? extends Image> images) {
581 NoSuchElementException exception = new NoSuchElementException(message);
582 if (logger.isTraceEnabled())
583 logger.warn(exception, "image ids that didn't match: %s", transform(images, imageToId));
584 throw exception;
585 }
586
587 protected Hardware resolveSize(Ordering<Hardware> hardwareOrdering, final Iterable<? extends Image> images) {
588 Set<? extends Hardware> hardwarel = hardwares.get();
589 Hardware hardware;
590 try {
591 Iterable<? extends Hardware> hardwaresThatAreCompatibleWithOurImages = filter(hardwarel,
592 new Predicate<Hardware>() {
593 @Override
594 public boolean apply(final Hardware hardware) {
595 return Iterables.any(images, new Predicate<Image>() {
596
597 @Override
598 public boolean apply(Image input) {
599 return hardware.supportsImage().apply(input);
600 }
601
602 @Override
603 public String toString() {
604 return "hardware(" + hardware + ").supportsImage()";
605 }
606
607 });
608
609 }
610 });
611 hardware = hardwareOrdering.max(filter(hardwaresThatAreCompatibleWithOurImages, hardwarePredicate));
612 } catch (NoSuchElementException exception) {
613 String message = format("no hardware profiles support images matching params: %s", toString());
614 exception = new NoSuchElementException(message);
615 if (logger.isTraceEnabled())
616 logger.warn(exception, "hardware profiles %s\nimage ids %s", hardwarel, transform(images, imageToId));
617 throw exception;
618 }
619 logger.debug("<< matched hardware(%s)", hardware.getId());
620 return hardware;
621 }
622
623 protected Ordering<Hardware> hardwareSorter() {
624 Ordering<Hardware> hardwareOrdering = DEFAULT_SIZE_ORDERING;
625 if (!biggest)
626 hardwareOrdering = hardwareOrdering.reverse();
627 if (fastest)
628 hardwareOrdering = Ordering.compound(ImmutableList.of(BY_CORES_ORDERING, hardwareOrdering));
629 return hardwareOrdering;
630 }
631
632
633
634
635
636
637
638
639 protected Image resolveImage(final Hardware hardware, Iterable<? extends Image> supportedImages) {
640 Predicate<Image> imagePredicate = new Predicate<Image>() {
641
642 @Override
643 public boolean apply(Image arg0) {
644 return hardware.supportsImage().apply(arg0);
645 }
646
647 @Override
648 public String toString() {
649 return "hardware(" + hardware + ").supportsImage()";
650 }
651 };
652 try {
653 Iterable<? extends Image> matchingImages = filter(supportedImages, imagePredicate);
654 if (logger.isTraceEnabled())
655 logger.trace("<< matched images(%s)", transform(matchingImages, imageToId));
656 List<? extends Image> maxImages = Lists2.multiMax(DEFAULT_IMAGE_ORDERING, matchingImages);
657 if (logger.isTraceEnabled())
658 logger.trace("<< best images(%s)", transform(maxImages, imageToId));
659 return maxImages.get(maxImages.size() - 1);
660 } catch (NoSuchElementException exception) {
661 throwNoSuchElementExceptionAfterLoggingImageIds(format("no image matched params: %s", toString()),
662 supportedImages);
663 assert false;
664 return null;
665 }
666 }
667
668 protected Set<? extends Image> getImages() {
669 return images.get();
670 }
671
672 private Predicate<Image> buildImagePredicate() {
673 List<Predicate<Image>> predicates = newArrayList();
674 if (imageId != null) {
675 predicates.add(idPredicate);
676 } else {
677 if (location != null)
678 predicates.add(new Predicate<Image>() {
679
680 @Override
681 public boolean apply(Image input) {
682 return locationPredicate.apply(input);
683 }
684
685 @Override
686 public String toString() {
687 return locationPredicate.toString();
688 }
689 });
690
691 final List<Predicate<OperatingSystem>> osPredicates = newArrayList();
692 if (osFamily != null)
693 osPredicates.add(osFamilyPredicate);
694 if (osName != null)
695 osPredicates.add(osNamePredicate);
696 if (osDescription != null)
697 osPredicates.add(osDescriptionPredicate);
698 if (osVersion != null)
699 osPredicates.add(osVersionPredicate);
700 if (os64Bit != null)
701 osPredicates.add(os64BitPredicate);
702 if (osArch != null)
703 osPredicates.add(osArchPredicate);
704 if (osPredicates.size() > 0)
705 predicates.add(new Predicate<Image>() {
706
707 @Override
708 public boolean apply(Image input) {
709 return and(osPredicates).apply(input.getOperatingSystem());
710 }
711
712 @Override
713 public String toString() {
714 return and(osPredicates).toString();
715 }
716
717 });
718 if (imageVersion != null)
719 predicates.add(imageVersionPredicate);
720 if (imageName != null)
721 predicates.add(imageNamePredicate);
722 if (imageDescription != null)
723 predicates.add(imageDescriptionPredicate);
724 if (imagePredicate != null)
725 predicates.add(imagePredicate);
726 }
727
728
729
730 Predicate<Image> imagePredicate = predicates.size() == 1 ? Iterables.<Predicate<Image>> get(predicates, 0)
731 : Predicates.<Image> and(predicates);
732 return imagePredicate;
733 }
734
735
736
737
738 @Override
739 public TemplateBuilder imageId(String imageId) {
740 this.imageId = imageId;
741 this.imageName = null;
742 this.imageDescription = null;
743 this.imagePredicate = null;
744 this.imageVersion = null;
745 this.osFamily = null;
746 this.osName = null;
747 this.osDescription = null;
748 this.osVersion = null;
749 this.os64Bit = null;
750 this.osArch = null;
751 return this;
752 }
753
754
755
756
757 @Override
758 public TemplateBuilder imageNameMatches(String nameRegex) {
759 this.imageName = nameRegex;
760 return this;
761 }
762
763
764
765
766 @Override
767 public TemplateBuilder imageDescriptionMatches(String descriptionRegex) {
768 this.imageDescription = descriptionRegex;
769 return this;
770 }
771
772
773
774
775 @Override
776 public TemplateBuilder imageMatches(Predicate<Image> condition) {
777 this.imagePredicate = condition;
778 return this;
779 }
780
781
782
783
784 @Override
785 public TemplateBuilder imageVersionMatches(String imageVersionRegex) {
786 this.imageVersion = imageVersionRegex;
787 return this;
788 }
789
790
791
792
793 @Override
794 public TemplateBuilder osVersionMatches(String osVersionRegex) {
795 this.osVersion = osVersionRegex;
796 return this;
797 }
798
799
800
801
802 @Override
803 public TemplateBuilder osArchMatches(String osArchitectureRegex) {
804 this.osArch = osArchitectureRegex;
805 return this;
806 }
807
808
809
810
811 @Override
812 public TemplateBuilder minCores(double minCores) {
813 this.minCores = minCores;
814 return this;
815 }
816
817
818
819
820 @Override
821 public TemplateBuilder minRam(int megabytes) {
822 this.minRam = megabytes;
823 return this;
824 }
825
826
827
828
829 @Override
830 public TemplateBuilder osNameMatches(String osNameRegex) {
831 this.osName = osNameRegex;
832 return this;
833 }
834
835
836
837
838 @Override
839 public TemplateBuilder osDescriptionMatches(String osDescriptionRegex) {
840 this.osDescription = osDescriptionRegex;
841 return this;
842 }
843
844
845
846
847 @Override
848 public TemplateBuilder hardwareId(String hardwareId) {
849 this.hardwareId = hardwareId;
850 return this;
851 }
852
853
854
855
856 @Override
857 public TemplateBuilder options(TemplateOptions options) {
858 this.options = optionsProvider.get();
859 checkNotNull(options, "options").copyTo(this.options);
860 return this;
861 }
862
863 @VisibleForTesting
864 boolean nothingChangedExceptOptions() {
865 return osFamily == null && location == null && imageId == null && hardwareId == null && osName == null
866 && imagePredicate == null && osDescription == null && imageVersion == null && osVersion == null
867 && osArch == null && os64Bit == null && imageName == null && imageDescription == null && minCores == 0
868 && minRam == 0 && !biggest && !fastest;
869 }
870
871
872
873
874 @Override
875 public TemplateBuilder any() {
876 return defaultTemplateProvider.get();
877 }
878
879 @Override
880 public String toString() {
881 return "[biggest=" + biggest + ", fastest=" + fastest + ", imageName=" + imageName + ", imageDescription="
882 + imageDescription + ", imageId=" + imageId + ", imagePredicate=" + imagePredicate + ", imageVersion=" + imageVersion + ", location=" + location
883 + ", minCores=" + minCores + ", minRam=" + minRam + ", osFamily=" + osFamily + ", osName=" + osName
884 + ", osDescription=" + osDescription + ", osVersion=" + osVersion + ", osArch=" + osArch + ", os64Bit="
885 + os64Bit + ", hardwareId=" + hardwareId + "]";
886 }
887
888 @Override
889 public TemplateBuilder os64Bit(boolean is64Bit) {
890 this.os64Bit = is64Bit;
891 return this;
892 }
893
894 }