| /** |
| * 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.config; |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; |
| import static org.jclouds.compute.config.ComputeServiceProperties.IMAGE_ID; |
| import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE; |
| import static org.jclouds.compute.domain.OsFamily.UBUNTU; |
| |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| import javax.inject.Named; |
| import javax.inject.Singleton; |
| |
| import org.jclouds.collect.Memoized; |
| import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput; |
| import org.jclouds.compute.callables.RunScriptOnNode; |
| import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh; |
| import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete; |
| import org.jclouds.compute.callables.RunScriptOnNodeUsingSsh; |
| import org.jclouds.compute.domain.ComputeMetadata; |
| import org.jclouds.compute.domain.Hardware; |
| import org.jclouds.compute.domain.Image; |
| import org.jclouds.compute.domain.NodeMetadata; |
| import org.jclouds.compute.domain.OsFamily; |
| import org.jclouds.compute.domain.Template; |
| import org.jclouds.compute.domain.TemplateBuilder; |
| import org.jclouds.compute.extensions.ImageExtension; |
| import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode; |
| import org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials; |
| import org.jclouds.compute.functions.TemplateOptionsToStatement; |
| import org.jclouds.compute.options.RunScriptOptions; |
| import org.jclouds.compute.options.TemplateOptions; |
| import org.jclouds.compute.reference.ComputeServiceConstants; |
| import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; |
| import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; |
| import org.jclouds.config.ValueOfConfigurationKeyOrNull; |
| import org.jclouds.domain.LoginCredentials; |
| import org.jclouds.json.Json; |
| import org.jclouds.location.Provider; |
| import org.jclouds.rest.AuthorizationException; |
| import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; |
| import org.jclouds.scriptbuilder.domain.Statement; |
| import org.jclouds.ssh.SshClient; |
| import org.jclouds.util.Suppliers2; |
| |
| import com.google.common.base.Function; |
| import com.google.common.base.Optional; |
| import com.google.common.base.Supplier; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Maps; |
| import com.google.inject.AbstractModule; |
| import com.google.inject.Inject; |
| import com.google.inject.Injector; |
| import com.google.inject.Provides; |
| import com.google.inject.TypeLiteral; |
| import com.google.inject.assistedinject.FactoryModuleBuilder; |
| import com.google.inject.name.Names; |
| |
| /** |
| * |
| * @author Adrian Cole |
| */ |
| public abstract class BaseComputeServiceContextModule extends AbstractModule { |
| |
| @Override |
| protected void configure() { |
| install(new ComputeServiceTimeoutsModule()); |
| bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() { |
| }).to(CreateSshClientOncePortIsListeningOnNode.class); |
| bind(new TypeLiteral<Function<TemplateOptions, Statement>>() { |
| }).to(TemplateOptionsToStatement.class); |
| bind(LoginCredentials.class).annotatedWith(Names.named("image")).toProvider( |
| GetLoginForProviderFromPropertiesAndStoreCredentialsOrReturnNull.class); |
| bind(new TypeLiteral<Function<Template, LoginCredentials>>() { |
| }).to(DefaultCredentialsFromImageOrOverridingCredentials.class); |
| |
| install(new FactoryModuleBuilder() |
| .implement(RunScriptOnNodeUsingSsh.class, Names.named("direct"), RunScriptOnNodeUsingSsh.class) |
| .implement(RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.class, Names.named("blocking"), |
| RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.class) |
| .implement(RunScriptOnNodeAsInitScriptUsingSsh.class, Names.named("nonblocking"), |
| RunScriptOnNodeAsInitScriptUsingSsh.class).build(RunScriptOnNodeFactoryImpl.Factory.class)); |
| |
| install(new PersistNodeCredentialsModule()); |
| |
| bind(RunScriptOnNode.Factory.class).to(RunScriptOnNodeFactoryImpl.class); |
| |
| install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() { |
| }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) |
| .implement(new TypeLiteral<Function<AtomicReference<NodeMetadata>, Void>>() { |
| }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class) |
| .build(CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class)); |
| |
| install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<RunScriptOnNode>>() { |
| }, InitializeRunScriptOnNodeOrPlaceInBadMap.class).build(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class)); |
| |
| install(new FactoryModuleBuilder().build(BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory.class)); |
| } |
| |
| @Singleton |
| static class RunScriptOnNodeFactoryImpl implements RunScriptOnNode.Factory { |
| |
| static interface Factory { |
| |
| @Named("direct") |
| RunScriptOnNodeUsingSsh exec(NodeMetadata node, Statement script, RunScriptOptions options); |
| |
| @Named("blocking") |
| RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete backgroundAndBlockOnComplete(NodeMetadata node, |
| Statement script, RunScriptOptions options); |
| |
| @Named("nonblocking") |
| RunScriptOnNodeAsInitScriptUsingSsh background(NodeMetadata node, Statement script, RunScriptOptions options); |
| } |
| |
| private final Factory factory; |
| |
| @Inject |
| RunScriptOnNodeFactoryImpl(Factory factory) { |
| this.factory = checkNotNull(factory, "factory"); |
| } |
| |
| @Override |
| public RunScriptOnNode create(NodeMetadata node, Statement runScript, RunScriptOptions options) { |
| checkNotNull(node, "node"); |
| checkNotNull(runScript, "runScript"); |
| checkNotNull(options, "options"); |
| return !options.shouldWrapInInitScript() ? factory.exec(node, runScript, options) : (options |
| .shouldBlockOnComplete() ? factory.backgroundAndBlockOnComplete(node, runScript, options) : factory |
| .background(node, runScript, options)); |
| } |
| |
| @Override |
| public BlockUntilInitScriptStatusIsZeroThenReturnOutput submit(NodeMetadata node, Statement script, |
| RunScriptOptions options) { |
| checkNotNull(node, "node"); |
| checkNotNull(script, "script"); |
| checkNotNull(options, "options"); |
| options.shouldWrapInInitScript(); |
| return factory.backgroundAndBlockOnComplete(node, script, options).init().future(); |
| } |
| } |
| |
| @Provides |
| @Singleton |
| public Map<OsFamily, Map<String, String>> provideOsVersionMap(ComputeServiceConstants.ReferenceData data, Json json) { |
| return json.fromJson(data.osVersionMapJson, new TypeLiteral<Map<OsFamily, Map<String, String>>>() { |
| }.getType()); |
| } |
| |
| /** |
| * The default template if none is provided. |
| */ |
| @Provides |
| @Named("DEFAULT") |
| protected TemplateBuilder provideTemplateOptionallyFromProperties(Injector injector, TemplateBuilder template, |
| @Provider String provider, ValueOfConfigurationKeyOrNull config) { |
| String templateString = config.apply(provider + ".template"); |
| if (templateString == null) |
| templateString = config.apply(TEMPLATE); |
| if (templateString != null) { |
| template.from(templateString); |
| } else { |
| template.osFamily(UBUNTU).osVersionMatches("1[012].[01][04]").os64Bit(true); |
| } |
| String imageId = config.apply(provider + ".image-id"); |
| if (imageId == null) |
| imageId = config.apply(IMAGE_ID); |
| if (imageId != null) |
| template.imageId(imageId); |
| return template; |
| } |
| |
| @Provides |
| @Singleton |
| protected Map<OsFamily, LoginCredentials> osFamilyToCredentials(Injector injector) { |
| return ImmutableMap.of(OsFamily.WINDOWS, LoginCredentials.builder().user("Administrator").build()); |
| } |
| |
| /** |
| * The default options if none are provided. |
| */ |
| @Provides |
| @Named("DEFAULT") |
| protected TemplateOptions provideTemplateOptions(Injector injector, TemplateOptions options) { |
| return options; |
| } |
| |
| @Provides |
| @Singleton |
| protected Supplier<Map<String, ? extends Image>> provideImageMap(@Memoized Supplier<Set<? extends Image>> images) { |
| return Suppliers2.compose(new Function<Set<? extends Image>, Map<String, ? extends Image>>() { |
| |
| @Override |
| public Map<String, ? extends Image> apply(Set<? extends Image> from) { |
| return Maps.uniqueIndex(from, new Function<Image, String>() { |
| |
| @Override |
| public String apply(Image from) { |
| return from.getId(); |
| } |
| |
| }); |
| } |
| |
| }, images); |
| } |
| |
| @Provides |
| @Singleton |
| @Memoized |
| protected Supplier<Set<? extends Image>> supplyImageCache(AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, |
| final Supplier<Set<? extends Image>> imageSupplier, Injector injector) { |
| if (shouldEagerlyParseImages(injector)) { |
| return supplyImageCache(authException, seconds, imageSupplier); |
| } else { |
| return supplyNonParsingImageCache(authException, seconds, imageSupplier, injector); |
| } |
| } |
| |
| protected boolean shouldEagerlyParseImages(Injector injector) { |
| return true; |
| } |
| |
| protected Supplier<Set<? extends Image>> supplyImageCache(AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, |
| final Supplier<Set<? extends Image>> imageSupplier) { |
| return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, imageSupplier, seconds, |
| TimeUnit.SECONDS); |
| } |
| |
| /** |
| * For overriding; default impl is same as {@link supplyImageCache(seconds, imageSupplier)} |
| */ |
| protected Supplier<Set<? extends Image>> supplyNonParsingImageCache(AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, |
| final Supplier<Set<? extends Image>> imageSupplier, Injector injector) { |
| return supplyImageCache(authException, seconds, imageSupplier); |
| } |
| |
| @Provides |
| @Singleton |
| protected Supplier<Map<String, ? extends Hardware>> provideSizeMap(@Memoized Supplier<Set<? extends Hardware>> sizes) { |
| return Suppliers2.compose(new Function<Set<? extends Hardware>, Map<String, ? extends Hardware>>() { |
| |
| @Override |
| public Map<String, ? extends Hardware> apply(Set<? extends Hardware> from) { |
| return Maps.uniqueIndex(from, new Function<Hardware, String>() { |
| |
| @Override |
| public String apply(Hardware from) { |
| return from.getId(); |
| } |
| |
| }); |
| } |
| |
| }, sizes); |
| } |
| |
| @Provides |
| @Singleton |
| @Memoized |
| protected Supplier<Set<? extends Hardware>> supplySizeCache(AtomicReference<AuthorizationException> authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, |
| final Supplier<Set<? extends Hardware>> hardwareSupplier) { |
| return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, hardwareSupplier, |
| seconds, TimeUnit.SECONDS); |
| } |
| |
| @Provides |
| @Singleton |
| protected Function<ComputeMetadata, String> indexer() { |
| return new Function<ComputeMetadata, String>() { |
| @Override |
| public String apply(ComputeMetadata from) { |
| return from.getProviderId(); |
| } |
| }; |
| } |
| |
| @Provides |
| @Singleton |
| protected Optional<ImageExtension> provideImageExtension(Injector i){ |
| return Optional.absent(); |
| } |
| |
| |
| } |