3838import org .apache .cloudstack .jobs .JobInfo ;
3939import org .apache .cloudstack .managed .context .ManagedContextExecutor ;
4040import org .apache .cloudstack .persistence .iactemplatesprofile .IacResourceTypeVO ;
41+ import org .apache .cloudstack .service .NimbleService ;
4142import org .apache .cloudstack .tosca .functions .ToscaFunction ;
4243import org .apache .cloudstack .tosca .model .ToscaInputDefinition ;
4344import org .apache .cloudstack .tosca .model .ToscaNodeTemplate ;
6566import java .util .Map ;
6667import java .util .Set ;
6768import java .util .concurrent .CompletableFuture ;
68- import java .util .concurrent .CompletionException ;
6969import java .util .concurrent .ExecutorService ;
7070import java .util .concurrent .Executors ;
71+ import java .util .concurrent .TimeUnit ;
72+ import java .util .concurrent .TimeoutException ;
7173import java .util .stream .Collectors ;
7274
7375public class ToscaOrchestrator {
@@ -99,10 +101,16 @@ public class ToscaOrchestrator {
99101 public void deployIacTemplate (String iacTemplateContent , Map <String , String > inputs ) {
100102 ToscaServiceTemplate serviceTemplate = toscaParser .parseServiceTemplate (iacTemplateContent , toscaProfile , null );
101103 resolveServiceTemplateInputs (serviceTemplate , inputs );
102- Map <String , CompletableFuture <String >> provisioningTasksFutures = createProvisioningTasksFutures (serviceTemplate );
104+ Map <String , CompletableFuture <Void >> provisioningTasksFutures = createProvisioningTasksFutures (serviceTemplate );
103105 logger .debug ("Awaiting for all the provisioning tasks of the node template to complete." );
104- CompletableFuture <Void > serviceTemplateFeature = CompletableFuture .allOf (provisioningTasksFutures .values ().toArray (new CompletableFuture [0 ]));
105- serviceTemplateFeature .join ();
106+ int iacTemplateExecutionTimeout = NimbleService .NimbleIaCTemplateExecutionTimeout .value ();
107+ CompletableFuture <Void > serviceTemplateFeature = CompletableFuture .allOf (provisioningTasksFutures .values ().toArray (new CompletableFuture [0 ]))
108+ .orTimeout (iacTemplateExecutionTimeout , TimeUnit .SECONDS );
109+ try {
110+ serviceTemplateFeature .join ();
111+ } catch (TimeoutException e ) {
112+
113+ }
106114 logger .info ("All provisioning tasks have completed successfully." );
107115 }
108116
@@ -145,24 +153,24 @@ private void handleGetInputFunctionCalls(String nodeTemplateName, ToscaProperty
145153 property .setEvaluatedValue (evaluatedValue );
146154 }
147155
148- private Map <String , CompletableFuture <String >> createProvisioningTasksFutures (ToscaServiceTemplate serviceTemplate ) {
156+ private Map <String , CompletableFuture <Void >> createProvisioningTasksFutures (ToscaServiceTemplate serviceTemplate ) {
149157 logger .debug ("Building provisioning tasks for the service template based on its graph topological sort." );
150- Map <String , CompletableFuture <String >> futures = new HashMap <>();
158+ Map <String , CompletableFuture <Void >> futures = new HashMap <>();
151159 CallContext callContext = CallContext .current ();
152160 getServiceTemplateTopologicalSort (serviceTemplate ).forEach ((node , dependencies ) -> {
153161 ToscaNodeTemplate nodeTemplate = serviceTemplate .getNodeTemplates ().get (node );
154- CompletableFuture <String > taskFuture ;
162+ CompletableFuture <Void > taskFuture ;
155163 if (dependencies .isEmpty ()) {
156164 logger .debug ("Node [{}] has no dependencies. Building its provisioning task, which will be ready to be allocated for execution." , node );
157- taskFuture = buildNodeProvisioningTask (nodeTemplate , callContext );
165+ taskFuture = provisionNode (nodeTemplate , callContext );
158166 } else {
159167 logger .debug ("Node [{}] has [{}] dependencies. Building its provisioning task, which will only be allocated for execution when all dependencies are ready." , node , dependencies .size ());
160168 CompletableFuture <?>[] dependenciesFutures = dependencies .stream ()
161169 .map ((dep ) -> futures .get (dep .getName ())).toArray (CompletableFuture []::new );
162170 taskFuture = CompletableFuture .allOf (dependenciesFutures ).thenCompose (v -> {
163171 logger .debug ("All dependencies of the node [{}] are ready. Building its provisioning task." , node );
164172 executeGetAttributeAndGetPropertyFunctionCalls (nodeTemplate , serviceTemplate );
165- return buildNodeProvisioningTask (nodeTemplate , callContext );
173+ return provisionNode (nodeTemplate , callContext );
166174 });
167175 }
168176
@@ -205,25 +213,12 @@ private void depthFirstSearch(LinkedHashMap<String, Set<ToscaNodeTemplate>> topo
205213 topologicalSort .put (node , graph .getOrDefault (node , Collections .emptySet ()));
206214 }
207215
208- private CompletableFuture <String > buildNodeProvisioningTask (ToscaNodeTemplate nodeTemplate , CallContext callContext ) {
209- return provisionNode (nodeTemplate , callContext )
210- // .orTimeout(5, TimeUnit.SECONDS)
211- .thenApply (result -> {
212- logger .debug ("SUCCESS [{}] [{}]" , nodeTemplate .getName (), Thread .currentThread ().getName ());
213- return result ;
214- }).exceptionally (ex -> {
215- logger .debug ("FAILURE [{}] [{}]" , nodeTemplate .getName (), ex );
216- throw new CompletionException (ex );
217- });
218- }
219-
220- private CompletableFuture <String > provisionNode (ToscaNodeTemplate nodeTemplate , CallContext callContext ) {
221- return CompletableFuture .supplyAsync (() -> {
216+ private CompletableFuture <Void > provisionNode (ToscaNodeTemplate nodeTemplate , CallContext callContext ) {
217+ return CompletableFuture .runAsync (() -> {
222218 CallContext .register (callContext , null );
223219 ManagedContextExecutor .execute (() -> {
224220 dispatchProvisioningCommand (nodeTemplate , callContext );
225221 });
226- return "res-" + nodeTemplate .getName ();
227222 }, executorPool );
228223 }
229224
@@ -242,8 +237,9 @@ private void dispatchProvisioningCommand(ToscaNodeTemplate nodeTemplate, CallCon
242237 logger .info ("Result of the [{}] execution: {}." , nodeTemplate .getName (), provisioningResult );
243238 populateNodeTemplateAttributes (nodeTemplate , provisioningResult );
244239 } catch (Exception e ) {
245- logger .error ("Could not instantiate the API class [{}]: {}." , apiClass .getName (), e .getMessage ());
246- throw new InvalidParameterValueException (String .format ("Could not dispatch the provisioning task of [%s]. Please, check the availability of the API associated with it." , nodeTemplate .getName ()));
240+ String errorMessage = String .format ("Could execute the provisioning API [%s] of the node template [%s]." , apiClass .getName (), nodeTemplate .getName ());
241+ logger .error (errorMessage , e );
242+ throw new CloudRuntimeException (errorMessage , e );
247243 }
248244 }
249245
0 commit comments