@Override
  public Set<? extends Location> get() {
    Set<? extends Location> regionsOrJustProvider = regionToProviderOrJustProvider.get();
    Set<String> zoneIds = zoneIdsSupplier.get();
    if (zoneIds.size() == 0) return regionsOrJustProvider;
    Map<String, Location> zoneIdToParent =
        setParentOfZoneToRegionOrProvider(zoneIds, regionsOrJustProvider);
    Map<String, Supplier<Set<String>>> isoCodesById = isoCodesByIdSupplier.get();

    Builder<Location> locations = ImmutableSet.builder();
    if (!Iterables.all(regionsOrJustProvider, LocationPredicates.isProvider()))
      locations.addAll(regionsOrJustProvider);
    for (Map.Entry<String, Location> entry : zoneIdToParent.entrySet()) {
      String zoneId = entry.getKey();
      Location parent = entry.getValue();
      LocationBuilder builder =
          new LocationBuilder()
              .scope(LocationScope.ZONE)
              .id(zoneId)
              .description(zoneId)
              .parent(parent);
      if (isoCodesById.containsKey(zoneId)) builder.iso3166Codes(isoCodesById.get(zoneId).get());
      // be cautious.. only inherit iso codes if the parent is a region
      // regions may be added dynamically, and we prefer to inherit an
      // empty set of codes from a region, then a provider, whose code
      // are likely hard-coded.
      else if (parent.getScope() == LocationScope.REGION)
        builder.iso3166Codes(parent.getIso3166Codes());
      locations.add(builder.build());
    }
    return locations.build();
  }
  private Map<String, Location> setParentOfZoneToRegionOrProvider(
      Set<String> zoneIds, Set<? extends Location> locations) {
    // mutable, so that we can query current state when adding. safe as its temporary
    Map<String, Location> zoneIdToParent = Maps.newLinkedHashMap();

    Location provider = Iterables.find(locations, LocationPredicates.isProvider(), null);
    if (locations.size() == 1 && provider != null) {
      for (String zone : zoneIds) zoneIdToParent.put(zone, provider);
    } else {
      // note that we only call regionIdToZoneIdsSupplier if there are region locations present
      // they cannot be, if the above is true
      Map<String, Supplier<Set<String>>> regionIdToZoneIds = regionIdToZoneIdsSupplier.get();
      for (Location region : Iterables.filter(locations, LocationPredicates.isRegion())) {
        provider = region.getParent();
        if (regionIdToZoneIds.containsKey(region.getId())) {
          for (String zoneId : regionIdToZoneIds.get(region.getId()).get())
            zoneIdToParent.put(zoneId, region);
        } else {
          logger.debug("no zones configured for region: %s", region);
        }
      }
    }

    SetView<String> orphans = Sets.difference(zoneIds, zoneIdToParent.keySet());
    if (orphans.size() > 0) {
      // any unmatched zones should have their parents set to the provider
      checkState(
          provider != null,
          "cannot configure zones %s as we need a parent, and the only available location [%s] is not a provider",
          zoneIds,
          locations);
      for (String orphanedZoneId : orphans) zoneIdToParent.put(orphanedZoneId, provider);
    }

    checkState(
        zoneIdToParent.keySet().containsAll(zoneIds),
        "orphaned zones: %s ",
        Sets.difference(zoneIds, zoneIdToParent.keySet()));
    return zoneIdToParent;
  }
 @Override
 public NodeMetadata apply(VirtualGuest from) {
   NodeMetadataBuilder builder = new NodeMetadataBuilder();
   builder.ids(from.getId() + "");
   builder.name(from.getHostname());
   builder.hostname(from.getFullyQualifiedDomainName());
   if (from.getDatacenter() != null) {
     builder.location(
         from(locations.get())
             .firstMatch(LocationPredicates.idEquals(from.getDatacenter().getName()))
             .orNull());
   }
   builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getHostname()));
   builder.hardware(virtualGuestToHardware.apply(from));
   Image image = virtualGuestToImage.apply(from);
   if (image != null) {
     builder.imageId(image.getId());
     builder.operatingSystem(image.getOperatingSystem());
   }
   if (from.getPowerState() != null) {
     builder.status(serverStateToNodeStatus.get(from.getPowerState().getKeyName()));
   }
   if (from.getPrimaryIpAddress() != null)
     builder.publicAddresses(ImmutableSet.of(from.getPrimaryIpAddress()));
   if (from.getPrimaryBackendIpAddress() != null)
     builder.privateAddresses(ImmutableSet.of(from.getPrimaryBackendIpAddress()));
   // TODO simplify once we move domain classes to AutoValue
   if (from.getOperatingSystem() != null
       && from.getOperatingSystem().getPasswords() != null
       && !from.getOperatingSystem().getPasswords().isEmpty()) {
     Password password = getBestPassword(from.getOperatingSystem().getPasswords(), from);
     builder.credentials(
         LoginCredentials.builder()
             .identity(password.getUsername())
             .credential(password.getPassword())
             .build());
   }
   if (from.getTagReferences() != null && !from.getTagReferences().isEmpty()) {
     List<String> tags = Lists.newArrayList();
     for (TagReference tagReference : from.getTagReferences()) {
       if (tagReference != null) {
         tags.add(tagReference.getTag().getName());
       }
     }
     builder.tags(tags);
   }
   return builder.build();
 }