1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.vcloud.binders;
20
21 import static com.google.common.base.Preconditions.checkArgument;
22 import static com.google.common.base.Preconditions.checkNotNull;
23 import static com.google.common.base.Preconditions.checkState;
24 import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
25 import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
26 import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
27
28 import java.net.URI;
29 import java.util.Map;
30 import java.util.Properties;
31 import java.util.Set;
32
33 import javax.annotation.Nullable;
34 import javax.annotation.Resource;
35 import javax.inject.Named;
36 import javax.inject.Singleton;
37 import javax.xml.parsers.FactoryConfigurationError;
38 import javax.xml.parsers.ParserConfigurationException;
39 import javax.xml.transform.TransformerException;
40
41 import org.jclouds.http.HttpRequest;
42 import org.jclouds.logging.Logger;
43 import org.jclouds.rest.MapBinder;
44 import org.jclouds.rest.binders.BindToStringPayload;
45 import org.jclouds.rest.internal.GeneratedHttpRequest;
46 import org.jclouds.vcloud.VCloudClient;
47 import org.jclouds.vcloud.domain.VAppTemplate;
48 import org.jclouds.vcloud.domain.Vm;
49 import org.jclouds.vcloud.domain.network.FenceMode;
50 import org.jclouds.vcloud.domain.network.NetworkConfig;
51 import org.jclouds.vcloud.endpoints.Network;
52 import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
53
54 import com.google.common.annotations.VisibleForTesting;
55 import com.google.common.base.Function;
56 import com.google.common.collect.ImmutableSet;
57 import com.google.common.collect.Iterables;
58 import com.google.common.collect.Sets;
59 import com.google.inject.Inject;
60 import com.jamesmurty.utils.XMLBuilder;
61
62
63
64
65
66
67 @Singleton
68 public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder {
69
70 protected final String ns;
71 protected final String schema;
72 protected final BindToStringPayload stringBinder;
73 protected final URI defaultNetwork;
74 protected final FenceMode defaultFenceMode;
75 protected final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate;
76 protected final VCloudClient client;
77
78 @Inject
79 public BindInstantiateVAppTemplateParamsToXmlPayload(DefaultNetworkNameInTemplate defaultNetworkNameInTemplate,
80 BindToStringPayload stringBinder, @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns,
81 @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema, @Network URI network,
82 @Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode, VCloudClient client) {
83 this.defaultNetworkNameInTemplate = defaultNetworkNameInTemplate;
84 this.ns = ns;
85 this.schema = schema;
86 this.stringBinder = stringBinder;
87 this.defaultNetwork = network;
88 this.defaultFenceMode = FenceMode.fromValue(fenceMode);
89 this.client = client;
90 }
91
92 @Override
93 public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
94 checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest<?>,
95 "this binder is only valid for GeneratedHttpRequests!");
96 GeneratedHttpRequest<?> gRequest = (GeneratedHttpRequest<?>) request;
97 checkState(gRequest.getArgs() != null, "args should be initialized at this point");
98 String name = checkNotNull(postParams.remove("name"), "name");
99 final URI template = URI.create(checkNotNull(postParams.remove("template"), "template"));
100
101 boolean deploy = true;
102 boolean powerOn = true;
103 Boolean customizeOnInstantiate = null;
104
105 Set<? extends NetworkConfig> networkConfig = null;
106
107 NetworkConfigDecorator networknetworkConfigDecorator = new NetworkConfigDecorator(template, defaultNetwork,
108 defaultFenceMode, defaultNetworkNameInTemplate);
109
110 InstantiateVAppTemplateOptions options = findOptionsInArgsOrNull(gRequest);
111
112 if (options != null) {
113 if (options.getNetworkConfig().size() > 0)
114 networkConfig = Sets.newLinkedHashSet(Iterables.transform(options.getNetworkConfig(),
115 networknetworkConfigDecorator));
116 deploy = ifNullDefaultTo(options.shouldDeploy(), deploy);
117 powerOn = ifNullDefaultTo(options.shouldPowerOn(), powerOn);
118 customizeOnInstantiate = options.shouldCustomizeOnInstantiate();
119 }
120
121 if (networkConfig == null)
122 networkConfig = ImmutableSet.of(networknetworkConfigDecorator.apply(null));
123
124 try {
125 return stringBinder.bindToRequest(
126 request,
127 generateXml(name, options.getDescription(), deploy, powerOn, template, networkConfig,
128 customizeOnInstantiate));
129 } catch (ParserConfigurationException e) {
130 throw new RuntimeException(e);
131 } catch (FactoryConfigurationError e) {
132 throw new RuntimeException(e);
133 } catch (TransformerException e) {
134 throw new RuntimeException(e);
135 }
136
137 }
138
139 @VisibleForTesting
140 Set<? extends Vm> ifCustomizationScriptIsSetGetVmsInTemplate(String customizationScript, final URI template) {
141 Set<? extends Vm> vms = Sets.newLinkedHashSet();
142 if (customizationScript != null) {
143 VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template);
144 checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template);
145 vms = vAppTemplate.getChildren();
146 checkArgument(vms.size() > 0, "no vms found in vAppTemplate %s", vAppTemplate);
147 }
148 return vms;
149 }
150
151 protected static final class NetworkConfigDecorator implements Function<NetworkConfig, NetworkConfig> {
152 private final URI template;
153 private final URI defaultNetwork;
154 private final FenceMode defaultFenceMode;
155 private final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate;
156
157 protected NetworkConfigDecorator(URI template, URI defaultNetwork, FenceMode defaultFenceMode,
158 DefaultNetworkNameInTemplate defaultNetworkNameInTemplate) {
159 this.template = checkNotNull(template, "template");
160 this.defaultNetwork = checkNotNull(defaultNetwork, "defaultNetwork");
161 this.defaultFenceMode = checkNotNull(defaultFenceMode, "defaultFenceMode");
162 this.defaultNetworkNameInTemplate = checkNotNull(defaultNetworkNameInTemplate, "defaultNetworkNameInTemplate");
163 }
164
165 @Override
166 public NetworkConfig apply(NetworkConfig from) {
167 if (from == null)
168 return new NetworkConfig(defaultNetworkNameInTemplate.apply(template), defaultNetwork, defaultFenceMode);
169 URI network = ifNullDefaultTo(from.getParentNetwork(), defaultNetwork);
170 FenceMode fenceMode = ifNullDefaultTo(from.getFenceMode(), defaultFenceMode);
171 String networkName = from.getNetworkName() != null ? from.getNetworkName() : defaultNetworkNameInTemplate
172 .apply(template);
173 return new NetworkConfig(networkName, network, fenceMode);
174 }
175 }
176
177 @Singleton
178 public static class DefaultNetworkNameInTemplate implements Function<URI, String> {
179 @Resource
180 protected Logger logger = Logger.NULL;
181
182 private final VCloudClient client;
183
184 @Inject
185 DefaultNetworkNameInTemplate(VCloudClient client) {
186 this.client = client;
187 }
188
189 @Override
190 public String apply(URI template) {
191 String networkName;
192 VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template);
193 checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template);
194 Set<org.jclouds.ovf.Network> networks = vAppTemplate.getNetworkSection().getNetworks();
195 checkArgument(networks.size() > 0, "no networks found in vAppTemplate %s", vAppTemplate);
196 if (networks.size() > 1)
197 logger.warn("multiple networks found for %s, choosing first from: %s", vAppTemplate.getName(), networks);
198 networkName = Iterables.get(networks, 0).getName();
199 return networkName;
200 }
201 }
202
203 protected String generateXml(String name, @Nullable String description, boolean deploy, boolean powerOn,
204 URI template, Iterable<? extends NetworkConfig> networkConfig, @Nullable Boolean customizeOnInstantiate)
205 throws ParserConfigurationException, FactoryConfigurationError, TransformerException {
206 XMLBuilder rootBuilder = buildRoot(name).a("deploy", deploy + "").a("powerOn", powerOn + "");
207 if (description != null)
208 rootBuilder.e("Description").t(description);
209 XMLBuilder instantiationParamsBuilder = rootBuilder.e("InstantiationParams");
210 addNetworkConfig(instantiationParamsBuilder, networkConfig);
211 addCustomizationConfig(instantiationParamsBuilder, customizeOnInstantiate);
212 rootBuilder.e("Source").a("href", template.toASCIIString());
213 rootBuilder.e("AllEULAsAccepted").t("true");
214
215 Properties outputProperties = new Properties();
216 outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
217 return rootBuilder.asString(outputProperties);
218 }
219
220 protected void addCustomizationConfig(XMLBuilder instantiationParamsBuilder, Boolean customizeOnInstantiate) {
221 if (customizeOnInstantiate != null) {
222
223
224
225
226 }
227 }
228
229 protected void addNetworkConfig(XMLBuilder instantiationParamsBuilder,
230 Iterable<? extends NetworkConfig> networkConfig) {
231 XMLBuilder networkConfigBuilder = instantiationParamsBuilder.e("NetworkConfigSection");
232 networkConfigBuilder.e("ovf:Info").t("Configuration parameters for logical networks");
233 for (NetworkConfig n : networkConfig) {
234 XMLBuilder configurationBuilder = networkConfigBuilder.e("NetworkConfig").a("networkName", n.getNetworkName())
235 .e("Configuration");
236 configurationBuilder.e("ParentNetwork").a("href", n.getParentNetwork().toASCIIString());
237 if (n.getFenceMode() != null) {
238 configurationBuilder.e("FenceMode").t(n.getFenceMode().toString());
239 }
240 }
241 }
242
243 protected XMLBuilder buildRoot(String name) throws ParserConfigurationException, FactoryConfigurationError {
244 return XMLBuilder.create("InstantiateVAppTemplateParams").a("name", name).a("xmlns", ns)
245 .a("xmlns:ovf", "http://schemas.dmtf.org/ovf/envelope/1");
246 }
247
248 protected InstantiateVAppTemplateOptions findOptionsInArgsOrNull(GeneratedHttpRequest<?> gRequest) {
249 for (Object arg : gRequest.getArgs()) {
250 if (arg instanceof InstantiateVAppTemplateOptions) {
251 return (InstantiateVAppTemplateOptions) arg;
252 } else if (arg instanceof InstantiateVAppTemplateOptions[]) {
253 InstantiateVAppTemplateOptions[] options = (InstantiateVAppTemplateOptions[]) arg;
254 return (options.length > 0) ? options[0] : null;
255 }
256 }
257 return null;
258 }
259
260 @Override
261 public <R extends HttpRequest> R bindToRequest(R request, Object input) {
262 throw new IllegalStateException("InstantiateVAppTemplateParams is needs parameters");
263 }
264
265 public static <T> T ifNullDefaultTo(T value, T defaultValue) {
266 return value != null ? value : checkNotNull(defaultValue, "defaultValue");
267 }
268 }