Add documentation of participant composition properties
[policy/parent.git] / docs / clamp / acm / acm-participant-guide.rst
1 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
2 .. http://creativecommons.org/licenses/by/4.0
3 .. Copyright (c) Nordix Foundation.  All rights reserved.
4
5 .. _acm-participant-guide-label:
6
7 Participant developer guide
8 ###########################
9
10 .. contents::
11     :depth: 4
12
13 The ACM runtime delegates the user requests to the participants for performing the actual operations.
14 Hence the participant module in ACM is implemented adhering to a list of ACM protocols along with their own functional logic.
15 It works in a contract with the Participant Intermediary module for communicating with ACM-R.
16 This guide explains the design considerations for a new participant implementation in ACM.
17
18 Please refer the following section for a detailed understanding of Inbound and outbound messages a participant interacts with.
19
20 .. toctree::
21    :maxdepth: 2
22
23    design-impl/participants/participants
24
25 Design considerations for a participant
26 ---------------------------------------
27
28 In ONAP, the ACM-runtime and participant modules are implemented in Java spring boot. The participant Intermediary module
29 which is added as a maven dependency to the participants has the default implementations available for listening the kafka
30 events coming in from the ACM-runtime, process them and delegate them to the appropriate handler class. Similarly the
31 Intermediary module also has the publisher class implementations for publishing events back from the participants to the ACM-runtime.
32
33 Hence the new participants has to have this Participant Intermediary module as a dependency and should:
34
35 * Configure SpringBoot to scan the components located into the package "org.onap.policy.clamp.acm.participant.intermediary".
36 * Implement the following interfaces from the Participant Intermediary.
37 * Provide the following mandatory properties in order to make the participant work in synchronisation with ACM-runtime.
38
39 The participant application should be provided with the following Intermediary parameter values in the application properties
40 and the same is configured for the 'ParticipantIntermediaryParameters' object in the code.
41
42 1. participantId - A unique participant UUID that is used by the runtime to identify the participant.
43 2. ReportingTimeIntervalMs - Time inertval the participant should report the status/heartbeat to the runtime.
44 3. clampAutomationCompositionTopics - This property takes in the kafka topic names and servers for the intermediary module to use.
45    These values should be provided for both source and sink configs. The following example shows the topic parameters set for using DMaap.
46
47 .. code-block:: bash
48
49     clampAutomationCompositionTopics:
50           topicSources:
51             -
52               topic: POLICY-ACRUNTIME-PARTICIPANT
53               servers:
54                 - ${topicServer:localhost}
55               topicCommInfrastructure: dmaap
56               fetchTimeout: 15000
57           topicSinks:
58             -
59               topic: POLICY-ACRUNTIME-PARTICIPANT
60               servers:
61                 - ${topicServer:localhost}
62               topicCommInfrastructure: dmaap
63
64 4. participantSupportedElementTypes - This property takes a list of typeName and typeVersion fields to define the types of AC elements the participant deals with.
65    These are user defined name and version and the same should be defined for the AC elements that are included in the TOSCA based AC definitions.
66
67 .. code-block:: bash
68
69     participantSupportedElementTypes:
70       -
71         typeName: org.onap.policy.clamp.acm.PolicyAutomationCompositionElement
72         typeVersion: 1.0.0
73
74 Interfaces to Implement
75 -----------------------
76 AutomationCompositionElementListener:
77   Every participant should implement a handler class that implements the AutomationCompositionElementListener interface
78   from the Participant Intermediary. The intermediary listener class listens for the incoming events from the ACM-runtime
79   and invoke the handler class implementations for various operations. This class implements the methods for deploying,
80   undeploying, locking, unlocking , deleting, updating, priming, depriming requests that are coming from the ACM-runtime.
81   The methods are as follows.
82
83 .. code-block:: java
84
85   1. void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException;
86   2. void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> inProperties) throws PfModelException;
87   3. void lock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException;
88   4. void unlock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException;
89   5. void delete(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException;
90   6. void update(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> inProperties) throws PfModelException;
91   7. void prime(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList) throws PfModelException;
92   8. void deprime(UUID compositionId) throws PfModelException;
93   9. void handleRestartComposition(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList, AcTypeState state) throws PfModelException;
94   10. void handleRestartInstance(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties, DeployState deployState, LockState lockState) throws PfModelException;
95
96 These method from the interface are implemented independently as per the user requirement. These methods after handling the
97 appropriate requests should also invoke the intermediary's publisher apis to notify the ACM-runtime with the acknowledgement events.
98
99 ParticipantParameters:
100   Every participant should implement a properties class that contains the values of all Intermediary parameter properties.
101   This class implements the method getIntermediaryParameters that returns 'ParticipantIntermediaryParameters' object. The method is as follows.
102
103 .. code-block:: java
104
105   ParticipantIntermediaryParameters getIntermediaryParameters()
106
107
108 APIs to invoke
109 --------------
110 ParticipantIntermediaryApi:
111   The participant intermediary api has the following methods that can be invoked from the participant for the following purposes.
112
113   #. The requested operations are completed in the handler class and the ACM-runtime needs to be notified.
114   #. Collect all instances data.
115   #. Send out Properties to ACM-runtime.
116
117   The methods are as follows:
118
119 This following method is invoked to update the AC element state after each operation is completed in the participant.
120
121 .. code-block:: java
122
123   1.  void updateAutomationCompositionElementState(UUID automationCompositionId, UUID elementId, DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message);
124   2.  Map<UUID, AutomationComposition> getAutomationCompositions();
125   3.  AutomationComposition getAutomationComposition(UUID automationCompositionId);
126   4.  AutomationCompositionElement getAutomationCompositionElement(UUID automationCompositionId, UUID elementId);
127   5.  Map<UUID, Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition>> getAcElementsDefinitions();
128   6.  Map<ToscaConceptIdentifier, AutomationCompositionElementDefinition> getAcElementsDefinitions(UUID compositionId);
129   7.  AutomationCompositionElementDefinition getAcElementDefinition(UUID compositionId, ToscaConceptIdentifier elementId);
130   8.  void sendAcDefinitionInfo(UUID compositionId, ToscaConceptIdentifier elementId, Map<String, Object> outProperties);
131   9.  void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult, String message);
132   10.  void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState, String operationalState, Map<String, Object> outProperties);
133
134 In/Out composition Properties
135 -----------------------------
136   The 'Common Properties' could be created or updated by ACM-runtime. Participants will receive that Properties during priming events.
137
138   The 'Out Properties' could be created or updated by participants. ACM-runtime will receive that Properties during ParticipantStatus event.
139   The participant can trigger this event using the method sendAcDefinitionInfo.
140
141   Is allowed to the participant to read all In/Out Properties of all compositions handled by the participant using the method getAcElementsDefinitions.
142   The following code is an example how to update the property 'myProperty' and send to ACM-runtime:
143
144 .. code-block:: java
145
146   var acElement = intermediaryApi.getAcElementDefinition(compositionId, elementId);
147   var outProperties = acElement.getOutProperties();
148   outProperties.put("myProperty", myProperty);
149   intermediaryApi.sendAcDefinitionInfo(compositionId, elementId, outProperties);
150
151 In/Out instance Properties
152 --------------------------
153   The 'In Properties' could be created or updated by ACM-runtime. Participants will receive that Properties during deploy and update events.
154
155   The 'Out Properties' could be created or updated by participants. ACM-runtime will receive that Properties during ParticipantStatus event.
156   The participant can trigger this event using the method sendAcElementInfo.
157   The 'useState' and 'operationalState' can be used as well.
158
159   Is allowed to the participant to read all In/Out Properties and state of all instances handled by the participant using the method getAutomationCompositions.
160   The following code is an example how to update the property 'myProperty' and send to ACM-runtime:
161
162 .. code-block:: java
163
164   var acElement = intermediaryApi.getAutomationCompositionElement(automationCompositionId, elementId);
165   var outProperties = acElement.getOutProperties();
166   outProperties.put("myProperty", myProperty);
167   intermediaryApi.sendAcElementInfo(automationCompositionId, elementId, acElement.getUseState(), acElement.getOperationalState(), outProperties);
168
169 Restart scenario
170 ----------------
171   Restart methods handle the scenario when participant shut down and restart.
172   The method handleRestartComposition will be called for each composition and will be present the 'state' at the time the participant shut down.
173   The method handleRestartInstance will be called for each instance element and will be present the 'deployState' and the 'lockState' at the time the participant shut down.
174
175 In ONAP, the following participants are already implemented in java spring boot for various requirements. The maven modules
176 can be referred here:
177
178   * `HTTP participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-http>`_.
179   * `Kubernetes participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-kubernetes>`_.
180   * `Policy participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-policy>`_.
181   * `A1PMS participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-a1pms>`_.
182   * `Kserve participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-kserve>`_.
183
184 Example of Implementation
185 -------------------------
186
187 This following code is an example of My First Participant:
188   * Application
189   * Parameters
190   * Handler
191
192 The Application class is configured to add the "org.onap.policy.clamp.acm.participant.intermediary" package in SpringBoot component scanning.
193
194 .. code-block:: java
195
196   @SpringBootApplication
197   @ComponentScan({
198     "org.onap.policy.clamp.acm.participant.myfirstparticipant",
199     "org.onap.policy.clamp.acm.participant.intermediary"
200   })
201   @ConfigurationPropertiesScan("org.onap.policy.clamp.acm.participant.myfirstparticipant.parameters")
202   public class MyFirstParticipantApplication {
203
204     public static void main(String[] args) {
205       SpringApplication.run(Application.class, args);
206     }
207   }
208
209 The Participant Parameters class implements the mandatory interface ParticipantParameters.
210 It could contains additional parameters.
211
212 .. code-block:: java
213
214   @Validated
215   @Getter
216   @Setter
217   @ConfigurationProperties(prefix = "participant")
218   public class ParticipantSimParameters implements ParticipantParameters {
219
220     @NotBlank
221     private String myparameter;
222
223     @NotNull
224     @Valid
225     private ParticipantIntermediaryParameters intermediaryParameters;
226   }
227
228 The following example shows the topic parameters and the additional 'myparameter'.
229
230 .. code-block:: bash
231
232   participant:
233     myparameter: my parameter
234     intermediaryParameters:
235       reportingTimeIntervalMs: 120000
236       description: Participant Description
237       participantId: 101c62b3-8918-41b9-a747-d21eb79c6c90
238       clampAutomationCompositionTopics:
239         topicSources:
240           - topic: POLICY-ACRUNTIME-PARTICIPANT
241             servers:
242               - ${topicServer:localhost}
243             topicCommInfrastructure: dmaap
244             fetchTimeout: 15000
245         topicSinks:
246           - topic: POLICY-ACRUNTIME-PARTICIPANT
247             servers:
248               - ${topicServer:localhost}
249             topicCommInfrastructure: dmaap
250       participantSupportedElementTypes:
251         -
252           typeName: org.onap.policy.clamp.acm.MyFirstAutomationCompositionElement
253           typeVersion: 1.0.0
254
255
256 The following example shows the Handler implementation and how could be the implemented the mandatory notifications.
257
258 .. code-block:: java
259
260   @Component
261   @RequiredArgsConstructor
262   public class MyFirstAcElementHandler implements AutomationCompositionElementListener {
263
264     private final ParticipantIntermediaryApi intermediaryApi;
265
266     @Override
267     public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
268             throws PfModelException {
269
270         // TODO deploy process
271
272         if (isDeploySuccess()) {
273             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
274                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
275         } else {
276             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
277                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
278         }
279     }
280
281     @Override
282     public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
283         LOGGER.debug("undeploy call");
284
285         // TODO undeploy process
286
287         if (isUndeploySuccess()) {
288             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
289                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
290                     "Undeployed");
291         } else {
292             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
293                     automationCompositionElementId, DeployState.DEPLOYED, null, StateChangeResult.FAILED,
294                     "Undeploy failed!");
295         }
296     }
297
298     @Override
299     public void lock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
300
301         // TODO lock process
302
303         if (isLockSuccess()) {
304             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
305                     automationCompositionElementId, null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
306         } else {
307             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
308                     automationCompositionElementId, null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
309         }
310     }
311
312     @Override
313     public void unlock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
314
315         // TODO unlock process
316
317         if (isUnlockSuccess()) {
318             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
319                     automationCompositionElementId, null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
320         } else {
321             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
322                     automationCompositionElementId, null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
323         }
324     }
325
326     @Override
327     public void delete(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
328
329         // TODO delete process
330
331         if (isDeleteSuccess()) {
332             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
333                     automationCompositionElementId, DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
334         } else {
335             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
336                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
337                     "Delete failed!");
338         }
339     }
340
341     @Override
342     public void update(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
343             throws PfModelException {
344
345         // TODO update process
346
347         if (isUpdateSuccess()) {
348             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
349                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
350         } else {
351             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
352                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
353         }
354     }
355
356     @Override
357     public void prime(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList)
358             throws PfModelException {
359
360         // TODO prime process
361
362         if (isPrimeSuccess()) {
363             intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR,
364                     "Primed");
365         } else {
366             intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.FAILED,
367                     "Prime failed!");
368         }
369     }
370
371     @Override
372     public void deprime(UUID compositionId) throws PfModelException {
373
374         // TODO deprime process
375
376         if (isDeprimeSuccess()) {
377             intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR,
378                     "Deprimed");
379         } else {
380             intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.FAILED,
381                     "Deprime failed!");
382         }
383     }
384
385
386     @Override
387     public void handleRestartComposition(UUID compositionId,
388             List<AutomationCompositionElementDefinition> elementDefinitionList, AcTypeState state)
389             throws PfModelException {
390
391         switch (state) {
392             case PRIMING:
393                 prime(compositionId, elementDefinitionList);
394                 break;
395
396             case DEPRIMING:
397                 // TODO restart process
398
399                 deprime(compositionId);
400                 break;
401
402             default:
403                 // TODO restart process
404
405                 intermediaryApi.updateCompositionState(compositionId, state, StateChangeResult.NO_ERROR, "Restarted");
406         }
407     }
408
409     @Override
410     public void handleRestartInstance(UUID automationCompositionId, AcElementDeploy element,
411             Map<String, Object> properties, DeployState deployState, LockState lockState) throws PfModelException {
412
413          // TODO restart process
414
415         if (DeployState.DEPLOYING.equals(deployState)) {
416             deploy(automationCompositionId, element, properties);
417             return;
418         }
419         if (DeployState.UNDEPLOYING.equals(deployState)) {
420             undeploy(automationCompositionId, element.getId());
421             return;
422         }
423         if (DeployState.UPDATING.equals(deployState)) {
424             update(automationCompositionId, element, properties);
425             return;
426         }
427         if (DeployState.DELETING.equals(deployState)) {
428             delete(automationCompositionId, element.getId());
429             return;
430         }
431         if (LockState.LOCKING.equals(lockState)) {
432             lock(automationCompositionId, element.getId());
433             return;
434         }
435         if (LockState.UNLOCKING.equals(lockState)) {
436             unlock(automationCompositionId, element.getId());
437             return;
438         }
439         intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
440                 deployState, lockState, StateChangeResult.NO_ERROR, "Restarted");
441     }
442
443