| 1 | /** | 
| 2 |  * | 
| 3 |  * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com> | 
| 4 |  * | 
| 5 |  * ==================================================================== | 
| 6 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
| 7 |  * you may not use this file except in compliance with the License. | 
| 8 |  * You may obtain a copy of the License at | 
| 9 |  * | 
| 10 |  * http://www.apache.org/licenses/LICENSE-2.0 | 
| 11 |  * | 
| 12 |  * Unless required by applicable law or agreed to in writing, software | 
| 13 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 14 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 15 |  * See the License for the specific language governing permissions and | 
| 16 |  * limitations under the License. | 
| 17 |  * ==================================================================== | 
| 18 |  */ | 
| 19 | package org.jclouds.compute.config; | 
| 20 |   | 
| 21 | import static com.google.common.base.Preconditions.checkNotNull; | 
| 22 | import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; | 
| 23 | import static org.jclouds.compute.domain.OsFamily.UBUNTU; | 
| 24 |   | 
| 25 | import java.util.Map; | 
| 26 | import java.util.Set; | 
| 27 | import java.util.concurrent.Callable; | 
| 28 | import java.util.concurrent.atomic.AtomicReference; | 
| 29 |   | 
| 30 | import javax.inject.Named; | 
| 31 | import javax.inject.Singleton; | 
| 32 |   | 
| 33 | import org.jclouds.collect.Memoized; | 
| 34 | import org.jclouds.compute.callables.RunScriptOnNode; | 
| 35 | import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh; | 
| 36 | import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete; | 
| 37 | import org.jclouds.compute.callables.RunScriptOnNodeUsingSsh; | 
| 38 | import org.jclouds.compute.domain.ComputeMetadata; | 
| 39 | import org.jclouds.compute.domain.Hardware; | 
| 40 | import org.jclouds.compute.domain.Image; | 
| 41 | import org.jclouds.compute.domain.NodeMetadata; | 
| 42 | import org.jclouds.compute.domain.OsFamily; | 
| 43 | import org.jclouds.compute.domain.TemplateBuilder; | 
| 44 | import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode; | 
| 45 | import org.jclouds.compute.functions.TemplateOptionsToStatement; | 
| 46 | import org.jclouds.compute.options.RunScriptOptions; | 
| 47 | import org.jclouds.compute.options.TemplateOptions; | 
| 48 | import org.jclouds.compute.reference.ComputeServiceConstants; | 
| 49 | import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; | 
| 50 | import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; | 
| 51 | import org.jclouds.json.Json; | 
| 52 | import org.jclouds.location.config.LocationModule; | 
| 53 | import org.jclouds.rest.AuthorizationException; | 
| 54 | import org.jclouds.rest.suppliers.RetryOnTimeOutButNotOnAuthorizationExceptionSupplier; | 
| 55 | import org.jclouds.scriptbuilder.domain.Statement; | 
| 56 | import org.jclouds.scriptbuilder.domain.Statements; | 
| 57 | import org.jclouds.ssh.SshClient; | 
| 58 |   | 
| 59 | import com.google.common.base.Function; | 
| 60 | import com.google.common.base.Supplier; | 
| 61 | import com.google.common.base.Suppliers; | 
| 62 | import com.google.common.collect.Maps; | 
| 63 | import com.google.inject.AbstractModule; | 
| 64 | import com.google.inject.Inject; | 
| 65 | import com.google.inject.Injector; | 
| 66 | import com.google.inject.Provides; | 
| 67 | import com.google.inject.TypeLiteral; | 
| 68 | import com.google.inject.assistedinject.FactoryModuleBuilder; | 
| 69 | import com.google.inject.name.Names; | 
| 70 |   | 
| 71 | /** | 
| 72 |  *  | 
| 73 |  * @author Adrian Cole | 
| 74 |  */ | 
| 75 | public abstract class BaseComputeServiceContextModule extends AbstractModule { | 
| 76 |    @Override | 
| 77 |    protected void configure() { | 
| 78 |       install(new LocationModule(authException)); | 
| 79 |       install(new ComputeServiceTimeoutsModule()); | 
| 80 |       bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() { | 
| 81 |       }).to(CreateSshClientOncePortIsListeningOnNode.class); | 
| 82 |       bind(new TypeLiteral<Function<TemplateOptions, Statement>>() { | 
| 83 |       }).to(TemplateOptionsToStatement.class); | 
| 84 |   | 
| 85 |       install(new FactoryModuleBuilder().implement(RunScriptOnNode.class, Names.named("direct"), | 
| 86 |                RunScriptOnNodeUsingSsh.class).implement(RunScriptOnNode.class, Names.named("blocking"), | 
| 87 |                RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.class).implement(RunScriptOnNode.class, | 
| 88 |                Names.named("nonblocking"), RunScriptOnNodeAsInitScriptUsingSsh.class).build( | 
| 89 |                RunScriptOnNodeFactoryImpl.Factory.class)); | 
| 90 |   | 
| 91 |       bind(RunScriptOnNode.Factory.class).to(RunScriptOnNodeFactoryImpl.class); | 
| 92 |   | 
| 93 |       install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<Void>>() { | 
| 94 |       }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).implement( | 
| 95 |                new TypeLiteral<Function<NodeMetadata, Void>>() { | 
| 96 |                }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).build( | 
| 97 |                CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class)); | 
| 98 |   | 
| 99 |       install(new FactoryModuleBuilder().implement(new TypeLiteral<Callable<RunScriptOnNode>>() { | 
| 100 |       }, InitializeRunScriptOnNodeOrPlaceInBadMap.class).build(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class)); | 
| 101 |    } | 
| 102 |   | 
| 103 |    @Singleton | 
| 104 |    static class RunScriptOnNodeFactoryImpl implements RunScriptOnNode.Factory { | 
| 105 |   | 
| 106 |       static interface Factory { | 
| 107 |   | 
| 108 |          @Named("direct") | 
| 109 |          RunScriptOnNode exec(NodeMetadata node, Statement script, RunScriptOptions options); | 
| 110 |   | 
| 111 |          @Named("blocking") | 
| 112 |          RunScriptOnNode backgroundAndBlockOnComplete(NodeMetadata node, Statement script, RunScriptOptions options); | 
| 113 |   | 
| 114 |          @Named("nonblocking") | 
| 115 |          RunScriptOnNode background(NodeMetadata node, Statement script, RunScriptOptions options); | 
| 116 |       } | 
| 117 |   | 
| 118 |       private final Factory factory; | 
| 119 |   | 
| 120 |       @Inject | 
| 121 |       RunScriptOnNodeFactoryImpl(Factory factory) { | 
| 122 |          this.factory = checkNotNull(factory, "factory"); | 
| 123 |       } | 
| 124 |   | 
| 125 |       @Override | 
| 126 |       public RunScriptOnNode create(NodeMetadata node, Statement runScript, RunScriptOptions options) { | 
| 127 |          checkNotNull(node, "node"); | 
| 128 |          checkNotNull(runScript, "runScript"); | 
| 129 |          checkNotNull(options, "options"); | 
| 130 |          return !options.shouldWrapInInitScript() ? factory.exec(node, runScript, options) : (options | 
| 131 |                   .shouldBlockOnComplete() ? factory.backgroundAndBlockOnComplete(node, runScript, options) : factory | 
| 132 |                   .background(node, runScript, options)); | 
| 133 |       } | 
| 134 |   | 
| 135 |       @Override | 
| 136 |       public RunScriptOnNode create(NodeMetadata node, String script) { | 
| 137 |          return create(node, Statements.exec(checkNotNull(script, "script"))); | 
| 138 |       } | 
| 139 |   | 
| 140 |       @Override | 
| 141 |       public RunScriptOnNode create(NodeMetadata node, Statement script) { | 
| 142 |          return create(node, script, RunScriptOptions.NONE); | 
| 143 |       } | 
| 144 |    } | 
| 145 |   | 
| 146 |    @Provides | 
| 147 |    @Singleton | 
| 148 |    public Map<OsFamily, Map<String, String>> provideOsVersionMap(ComputeServiceConstants.ReferenceData data, Json json) { | 
| 149 |       return json.fromJson(data.osVersionMapJson, new TypeLiteral<Map<OsFamily, Map<String, String>>>() { | 
| 150 |       }.getType()); | 
| 151 |    } | 
| 152 |   | 
| 153 |    /** | 
| 154 |     * The default template if none is provided. | 
| 155 |     */ | 
| 156 |    @Provides | 
| 157 |    @Named("DEFAULT") | 
| 158 |    protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) { | 
| 159 |       return template.osFamily(UBUNTU).osVersionMatches("10.04").os64Bit(true); | 
| 160 |    } | 
| 161 |   | 
| 162 |    /** | 
| 163 |     * supplies how the tag is encoded into the name. A string of hex characters is the last argument | 
| 164 |     * and tag is the first | 
| 165 |     */ | 
| 166 |    @Provides | 
| 167 |    @Named("NAMING_CONVENTION") | 
| 168 |    @Singleton | 
| 169 |    protected String provideNamingConvention() { | 
| 170 |       return "%s-%s"; | 
| 171 |    } | 
| 172 |   | 
| 173 |    protected AtomicReference<AuthorizationException> authException = new AtomicReference<AuthorizationException>(); | 
| 174 |   | 
| 175 |    @Provides | 
| 176 |    @Singleton | 
| 177 |    protected Supplier<Map<String, ? extends Image>> provideImageMap(@Memoized Supplier<Set<? extends Image>> images) { | 
| 178 |       return Suppliers.compose(new Function<Set<? extends Image>, Map<String, ? extends Image>>() { | 
| 179 |   | 
| 180 |          @Override | 
| 181 |          public Map<String, ? extends Image> apply(Set<? extends Image> from) { | 
| 182 |             return Maps.uniqueIndex(from, new Function<Image, String>() { | 
| 183 |   | 
| 184 |                @Override | 
| 185 |                public String apply(Image from) { | 
| 186 |                   return from.getId(); | 
| 187 |                } | 
| 188 |   | 
| 189 |             }); | 
| 190 |          } | 
| 191 |   | 
| 192 |       }, images); | 
| 193 |    } | 
| 194 |   | 
| 195 |    @Provides | 
| 196 |    @Singleton | 
| 197 |    @Memoized | 
| 198 |    protected Supplier<Set<? extends Image>> supplyImageCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, | 
| 199 |             final Supplier<Set<? extends Image>> imageSupplier) { | 
| 200 |       return new RetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Set<? extends Image>>(authException, seconds, | 
| 201 |                new Supplier<Set<? extends Image>>() { | 
| 202 |                   @Override | 
| 203 |                   public Set<? extends Image> get() { | 
| 204 |                      return imageSupplier.get(); | 
| 205 |                   } | 
| 206 |                }); | 
| 207 |    } | 
| 208 |   | 
| 209 |    @Provides | 
| 210 |    @Singleton | 
| 211 |    protected Supplier<Map<String, ? extends Hardware>> provideSizeMap(@Memoized Supplier<Set<? extends Hardware>> sizes) { | 
| 212 |       return Suppliers.compose(new Function<Set<? extends Hardware>, Map<String, ? extends Hardware>>() { | 
| 213 |   | 
| 214 |          @Override | 
| 215 |          public Map<String, ? extends Hardware> apply(Set<? extends Hardware> from) { | 
| 216 |             return Maps.uniqueIndex(from, new Function<Hardware, String>() { | 
| 217 |   | 
| 218 |                @Override | 
| 219 |                public String apply(Hardware from) { | 
| 220 |                   return from.getId(); | 
| 221 |                } | 
| 222 |   | 
| 223 |             }); | 
| 224 |          } | 
| 225 |   | 
| 226 |       }, sizes); | 
| 227 |    } | 
| 228 |   | 
| 229 |    @Provides | 
| 230 |    @Singleton | 
| 231 |    @Memoized | 
| 232 |    protected Supplier<Set<? extends Hardware>> supplySizeCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, | 
| 233 |             final Supplier<Set<? extends Hardware>> hardwareSupplier) { | 
| 234 |       return new RetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Set<? extends Hardware>>(authException, seconds, | 
| 235 |                new Supplier<Set<? extends Hardware>>() { | 
| 236 |                   @Override | 
| 237 |                   public Set<? extends Hardware> get() { | 
| 238 |                      return hardwareSupplier.get(); | 
| 239 |                   } | 
| 240 |                }); | 
| 241 |    } | 
| 242 |   | 
| 243 |    @Provides | 
| 244 |    @Singleton | 
| 245 |    protected Function<ComputeMetadata, String> indexer() { | 
| 246 |       return new Function<ComputeMetadata, String>() { | 
| 247 |          @Override | 
| 248 |          public String apply(ComputeMetadata from) { | 
| 249 |             return from.getProviderId(); | 
| 250 |          } | 
| 251 |       }; | 
| 252 |    } | 
| 253 |   | 
| 254 | } |