/* * 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.Collections; import java.util.Map; import javax.annotation.Nullable; import org.apache.brooklyn.api.location.LocationSpec; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.exceptions.CompoundRuntimeException; import org.apache.brooklyn.util.exceptions.Exceptions; import org.jclouds.compute.ComputeService; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Template; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Throwables; import com.google.common.collect.Iterables; import com.google.common.reflect.TypeToken; public class BailOutJcloudsLocation extends JcloudsLocation { public static final String ERROR_MESSAGE = "early termination for test"; public static final RuntimeException BAIL_OUT_FOR_TESTING = new RuntimeException(ERROR_MESSAGE); // Don't care which image; not actually provisioning private static final String US_EAST_IMAGE_ID = "us-east-1/ami-7d7bfc14"; public static final ConfigKey<Function<ConfigBag, Void>> BUILD_TEMPLATE_INTERCEPTOR = ConfigKeys.newConfigKey( new TypeToken<Function<ConfigBag, Void>>() {}, "buildtemplateinterceptor"); public static final ConfigKey<Boolean> BUILD_TEMPLATE = ConfigKeys.newBooleanConfigKey( "buildtemplate"); ConfigBag lastConfigBag; Template template; public BailOutJcloudsLocation() { super(); } public BailOutJcloudsLocation(Map<?, ?> conf) { super(conf); } @Override public Template buildTemplate(ComputeService computeService, ConfigBag config) { lastConfigBag = config; if (getConfig(BUILD_TEMPLATE_INTERCEPTOR) != null) { getConfig(BUILD_TEMPLATE_INTERCEPTOR).apply(config); } if (Boolean.TRUE.equals(getConfig(BUILD_TEMPLATE))) { template = super.buildTemplate(computeService, config); } throw new RuntimeException(BAIL_OUT_FOR_TESTING); } public Template getTemplate() { return template; } public void tryObtain() { tryObtain(Collections.emptyMap()); } public void tryObtain(Map<?, ?> flags) { tryObtainAndCheck(flags, Predicates.alwaysTrue()); } public void tryObtainAndCheck(Map<?, ?> flags, Predicate<? super ConfigBag> test) { try { obtain(flags); } catch (Exception e) { boolean found = Iterables.tryFind(Throwables.getCausalChain(e), Predicates.<Throwable>equalTo(e)).isPresent(); if (!found && e instanceof CompoundRuntimeException) { for (Throwable cause : ((CompoundRuntimeException) e).getAllCauses()) { found = Iterables.tryFind(Throwables.getCausalChain(cause), Predicates.<Throwable>equalTo(e)).isPresent(); if (found) break; } } if (found) { test.apply(lastConfigBag); } else { throw Exceptions.propagate(e); } } } @Override @VisibleForTesting public UserCreation createUserStatements(@Nullable Image image, ConfigBag config) { return super.createUserStatements(image, config); } public static BailOutJcloudsLocation newBailOutJcloudsLocation(ManagementContext mgmt) { return newBailOutJcloudsLocation(mgmt, Collections.<ConfigKey<?>, Object>emptyMap()); } public static BailOutJcloudsLocation newBailOutJcloudsLocation(ManagementContext mgmt, Map<ConfigKey<?>, ?> config) { Map<ConfigKey<?>, ?> allConfig = MutableMap.<ConfigKey<?>, Object>builder() .put(IMAGE_ID, "bogus") .put(CLOUD_PROVIDER, "aws-ec2") .put(ACCESS_IDENTITY, "bogus") .put(CLOUD_REGION_ID, "bogus") .put(ACCESS_CREDENTIAL, "bogus") .put(USER, "fred") .put(MIN_RAM, 16) .put(JcloudsLocation.MACHINE_CREATE_ATTEMPTS, 1) .putAll(config) .build(); return mgmt.getLocationManager().createLocation( LocationSpec.create(BailOutJcloudsLocation.class).configure(allConfig)); } // todo better name /** As {@link BailOutJcloudsLocation}, counting the number of {@link #buildTemplate} calls. */ public static class CountingBailOutJcloudsLocation extends BailOutJcloudsLocation { int buildTemplateCount = 0; @Override public Template buildTemplate(ComputeService computeService, ConfigBag config) { buildTemplateCount++; return super.buildTemplate(computeService, config); } } public static CountingBailOutJcloudsLocation newCountingBailOutJcloudsLocation(ManagementContext mgmt, Map flags) { LocationSpec<CountingBailOutJcloudsLocation> spec = LocationSpec.create(CountingBailOutJcloudsLocation.class) .configure(flags); return mgmt.getLocationManager().createLocation(spec); } /** @see #newBailOutJcloudsLocationForLiveTest(LocalManagementContext, Map)} */ public static BailOutJcloudsLocation newBailOutJcloudsLocationForLiveTest(LocalManagementContext mgmt) { return newBailOutJcloudsLocationForLiveTest(mgmt, Collections.<ConfigKey<?>, Object>emptyMap()); } /** * Takes identity and access credential from management context's Brooklyn properties and sets * inbound ports to [22, 80, 9999]. */ public static BailOutJcloudsLocation newBailOutJcloudsLocationForLiveTest(LocalManagementContext mgmt, Map<ConfigKey<?>, ?> config) { BrooklynProperties brooklynProperties = mgmt.getBrooklynProperties(); String identity = (String) brooklynProperties.get("brooklyn.location.jclouds.aws-ec2.identity"); if (identity == null) identity = (String) brooklynProperties.get("brooklyn.jclouds.aws-ec2.identity"); String credential = (String) brooklynProperties.get("brooklyn.location.jclouds.aws-ec2.credential"); if (credential == null) credential = (String) brooklynProperties.get("brooklyn.jclouds.aws-ec2.credential"); Map<ConfigKey<?>, ?> allConfig = MutableMap.<ConfigKey<?>, Object>builder() .put(CLOUD_PROVIDER, AbstractJcloudsLiveTest.AWS_EC2_PROVIDER) .put(CLOUD_REGION_ID, AbstractJcloudsLiveTest.AWS_EC2_USEAST_REGION_NAME) .put(IMAGE_ID, US_EAST_IMAGE_ID) // so Brooklyn does not attempt to load all EC2 images .put(ACCESS_IDENTITY, identity) .put(ACCESS_CREDENTIAL, credential) .put(INBOUND_PORTS, "[22, 80, 9999]") .put(BUILD_TEMPLATE, true) .putAll(config) .build(); return newBailOutJcloudsLocation(mgmt, allConfig); } }