9228ca371bc116950f9a7af1fdef842da292e435
[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.  void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState, String operationalState, Map<String, Object> outProperties);
126   4.  void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult, String message);
127
128 In/Out Properties
129 -----------------
130   The 'In Properties' could be created or updated by ACM-runtime. Participants will receive that Properties during deploy and update events.
131
132   The 'Out Properties' could be created or updated by participants. ACM-runtime will receive that Properties during ParticipantStatus event.
133   The participant can trigger this event using the method sendAcElementInfo.
134   The 'useState' and 'operationalState' can be used as well.
135
136   Is allowed to the participant to read all In/Out Properties and state of all instances handled by the participant using the method getAutomationCompositions.
137   The following code is an example how to update the property 'myProperty' and send to ACM-runtime:
138
139 .. code-block:: java
140
141   var automationCompositions = intermediaryApi.getAutomationCompositions();
142   var automationComposition = automationCompositions.get(automationCompositionId);
143   var acElement = automationComposition.getElements().get(elementId);
144   var outProperties = acElement.getOutProperties();
145   outProperties.put("myProperty", myProperty);
146   intermediaryApi.sendAcElementInfo(automationCompositionId, elementId, acElement.getUseState(), acElement.getOperationalState(), outProperties);
147
148 Restart scenario
149 ----------------
150   Restart methods handle the scenario when participant shut down and restart.
151   The method handleRestartComposition will be called for each composition and will be present the 'state' at the time the participant shut down.
152   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.
153
154 In ONAP, the following participants are already implemented in java spring boot for various requirements. The maven modules
155 can be referred here:
156
157   * `HTTP participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-http>`_.
158   * `Kubernetes participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-kubernetes>`_.
159   * `Policy participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-policy>`_.
160   * `A1PMS participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-a1pms>`_.
161   * `Kserve participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-kserve>`_.
162
163 Example of Implementation
164 -------------------------
165
166 This following code is an example of My First Participant:
167   * Application
168   * Parameters
169   * Handler
170
171 The Application class is configured to add the "org.onap.policy.clamp.acm.participant.intermediary" package in SpringBoot component scanning.
172
173 .. code-block:: java
174
175   @SpringBootApplication
176   @ComponentScan({
177     "org.onap.policy.clamp.acm.participant.myfirstparticipant",
178     "org.onap.policy.clamp.acm.participant.intermediary"
179   })
180   @ConfigurationPropertiesScan("org.onap.policy.clamp.acm.participant.myfirstparticipant.parameters")
181   public class MyFirstParticipantApplication {
182
183     public static void main(String[] args) {
184       SpringApplication.run(Application.class, args);
185     }
186   }
187
188 The Participant Parameters class implements the mandatory interface ParticipantParameters.
189 It could contains additional parameters.
190
191 .. code-block:: java
192
193   @Validated
194   @Getter
195   @Setter
196   @ConfigurationProperties(prefix = "participant")
197   public class ParticipantSimParameters implements ParticipantParameters {
198
199     @NotBlank
200     private String myparameter;
201
202     @NotNull
203     @Valid
204     private ParticipantIntermediaryParameters intermediaryParameters;
205   }
206
207 The following example shows the topic parameters and the additional 'myparameter'.
208
209 .. code-block:: bash
210
211   participant:
212     myparameter: my parameter
213     intermediaryParameters:
214       reportingTimeIntervalMs: 120000
215       description: Participant Description
216       participantId: 101c62b3-8918-41b9-a747-d21eb79c6c90
217       clampAutomationCompositionTopics:
218         topicSources:
219           - topic: POLICY-ACRUNTIME-PARTICIPANT
220             servers:
221               - ${topicServer:localhost}
222             topicCommInfrastructure: dmaap
223             fetchTimeout: 15000
224         topicSinks:
225           - topic: POLICY-ACRUNTIME-PARTICIPANT
226             servers:
227               - ${topicServer:localhost}
228             topicCommInfrastructure: dmaap
229       participantSupportedElementTypes:
230         -
231           typeName: org.onap.policy.clamp.acm.MyFirstAutomationCompositionElement
232           typeVersion: 1.0.0
233
234
235 The following example shows the Handler implementation and how could be the implemented the mandatory notifications.
236
237 .. code-block:: java
238
239   @Component
240   @RequiredArgsConstructor
241   public class MyFirstAcElementHandler implements AutomationCompositionElementListener {
242
243     private final ParticipantIntermediaryApi intermediaryApi;
244
245     @Override
246     public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
247             throws PfModelException {
248
249         // TODO deploy process
250
251         if (isDeploySuccess()) {
252             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
253                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
254         } else {
255             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
256                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
257         }
258     }
259
260     @Override
261     public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
262         LOGGER.debug("undeploy call");
263
264         // TODO undeploy process
265
266         if (isUndeploySuccess()) {
267             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
268                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
269                     "Undeployed");
270         } else {
271             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
272                     automationCompositionElementId, DeployState.DEPLOYED, null, StateChangeResult.FAILED,
273                     "Undeploy failed!");
274         }
275     }
276
277     @Override
278     public void lock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
279
280         // TODO lock process
281
282         if (isLockSuccess()) {
283             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
284                     automationCompositionElementId, null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
285         } else {
286             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
287                     automationCompositionElementId, null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
288         }
289     }
290
291     @Override
292     public void unlock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
293
294         // TODO unlock process
295
296         if (isUnlockSuccess()) {
297             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
298                     automationCompositionElementId, null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
299         } else {
300             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
301                     automationCompositionElementId, null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
302         }
303     }
304
305     @Override
306     public void delete(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
307
308         // TODO delete process
309
310         if (isDeleteSuccess()) {
311             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
312                     automationCompositionElementId, DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
313         } else {
314             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
315                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
316                     "Delete failed!");
317         }
318     }
319
320     @Override
321     public void update(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
322             throws PfModelException {
323
324         // TODO update process
325
326         if (isUpdateSuccess()) {
327             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
328                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
329         } else {
330             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
331                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
332         }
333     }
334
335     @Override
336     public void prime(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList)
337             throws PfModelException {
338
339         // TODO prime process
340
341         if (isPrimeSuccess()) {
342             intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR,
343                     "Primed");
344         } else {
345             intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.FAILED,
346                     "Prime failed!");
347         }
348     }
349
350     @Override
351     public void deprime(UUID compositionId) throws PfModelException {
352
353         // TODO deprime process
354
355         if (isDeprimeSuccess()) {
356             intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR,
357                     "Deprimed");
358         } else {
359             intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.FAILED,
360                     "Deprime failed!");
361         }
362     }
363
364
365     @Override
366     public void handleRestartComposition(UUID compositionId,
367             List<AutomationCompositionElementDefinition> elementDefinitionList, AcTypeState state)
368             throws PfModelException {
369
370         switch (state) {
371             case PRIMING:
372                 prime(compositionId, elementDefinitionList);
373                 break;
374
375             case DEPRIMING:
376                 // TODO restart process
377
378                 deprime(compositionId);
379                 break;
380
381             default:
382                 // TODO restart process
383
384                 intermediaryApi.updateCompositionState(compositionId, state, StateChangeResult.NO_ERROR, "Restarted");
385         }
386     }
387
388     @Override
389     public void handleRestartInstance(UUID automationCompositionId, AcElementDeploy element,
390             Map<String, Object> properties, DeployState deployState, LockState lockState) throws PfModelException {
391
392          // TODO restart process
393
394         if (DeployState.DEPLOYING.equals(deployState)) {
395             deploy(automationCompositionId, element, properties);
396             return;
397         }
398         if (DeployState.UNDEPLOYING.equals(deployState)) {
399             undeploy(automationCompositionId, element.getId());
400             return;
401         }
402         if (DeployState.UPDATING.equals(deployState)) {
403             update(automationCompositionId, element, properties);
404             return;
405         }
406         if (DeployState.DELETING.equals(deployState)) {
407             delete(automationCompositionId, element.getId());
408             return;
409         }
410         if (LockState.LOCKING.equals(lockState)) {
411             lock(automationCompositionId, element.getId());
412             return;
413         }
414         if (LockState.UNLOCKING.equals(lockState)) {
415             unlock(automationCompositionId, element.getId());
416             return;
417         }
418         intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
419                 deployState, lockState, StateChangeResult.NO_ERROR, "Restarted");
420     }
421
422