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 | } |