4ce979e09ad26d7b9b8a1e8df112718ae67f33bc
[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
94 These method from the interface are implemented independently as per the user requirement. These methods after handling the
95 appropriate requests should also invoke the intermediary's publisher apis to notify the ACM-runtime with the acknowledgement events.
96
97 ParticipantParameters:
98   Every participant should implement a properties class that contains the values of all Intermediary parameter properties.
99   This class implements the method getIntermediaryParameters that returns 'ParticipantIntermediaryParameters' object. The method is as follows.
100
101 .. code-block:: java
102
103   ParticipantIntermediaryParameters getIntermediaryParameters()
104
105
106 APIs to invoke
107 --------------
108 ParticipantIntermediaryApi:
109   The participant intermediary api has the following methods that can be invoked from the participant for the following purposes.
110
111   #. The requested operations are completed in the handler class and the ACM-runtime needs to be notified.
112   #. Collect all instances data.
113   #. Send out Properties to ACM-runtime.
114
115   The methods are as follows:
116
117 This following method is invoked to update the AC element state after each operation is completed in the participant.
118
119 .. code-block:: java
120
121   1.  void updateAutomationCompositionElementState(UUID automationCompositionId, UUID elementId, DeployState deployState, LockState lockState, StateChangeResult stateChangeResult, String message);
122   2.  Map<UUID, AutomationComposition> getAutomationCompositions();
123   3.  void sendAcElementInfo(UUID automationCompositionId, UUID elementId, String useState, String operationalState, Map<String, Object> outProperties);
124   4.  void updateCompositionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult, String message);
125
126 In/Out Properties
127 -----------------
128   The 'In Properties' could be created or updated by ACM-runtime. Participants will receive that Properties during deploy and update events.
129
130   The 'Out Properties' could be created or updated by participants. ACM-runtime will receive that Properties during ParticipantStatus event.
131   The participant can trigger this event using the method sendAcElementInfo.
132   The 'useState' and 'operationalState' can be used as well.
133
134   Is allowed to the participant to read all In/Out Properties and state of all instances handled by the participant using the method getAutomationCompositions.
135   The following code is an example how to update the property 'myProperty' and send to ACM-runtime:
136
137 .. code-block:: java
138
139   var automationCompositions = intermediaryApi.getAutomationCompositions();
140   var automationComposition = automationCompositions.get(automationCompositionId);
141   var acElement = automationComposition.getElements().get(elementId);
142   var outProperties = acElement.getOutProperties();
143   outProperties.put("myProperty", myProperty);
144   intermediaryApi.sendAcElementInfo(automationCompositionId, elementId, acElement.getUseState(), acElement.getOperationalState(), outProperties);
145
146
147
148 In ONAP, the following participants are already implemented in java spring boot for various requirements. The maven modules
149 can be referred here:
150
151   * `HTTP participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-http>`_.
152   * `Kubernetes participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-kubernetes>`_.
153   * `Policy participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-policy>`_.
154   * `A1PMS participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-a1pms>`_.
155   * `Kserve participant <https://github.com/onap/policy-clamp/tree/master/participant/participant-impl/participant-impl-kserve>`_.
156
157 Example of Implementation
158 -------------------------
159
160 This following code is an example of My First Participant:
161   * Application
162   * Parameters
163   * Handler
164
165 The Application class is configured to add the "org.onap.policy.clamp.acm.participant.intermediary" package in SpringBoot component scanning.
166
167 .. code-block:: java
168
169   @SpringBootApplication
170   @ComponentScan({
171     "org.onap.policy.clamp.acm.participant.myfirstparticipant",
172     "org.onap.policy.clamp.acm.participant.intermediary"
173   })
174   @ConfigurationPropertiesScan("org.onap.policy.clamp.acm.participant.myfirstparticipant.parameters")
175   public class MyFirstParticipantApplication {
176
177     public static void main(String[] args) {
178       SpringApplication.run(Application.class, args);
179     }
180   }
181
182 The Participant Parameters class implements the mandatory interface ParticipantParameters.
183 It could contains additional parameters.
184
185 .. code-block:: java
186
187   @Validated
188   @Getter
189   @Setter
190   @ConfigurationProperties(prefix = "participant")
191   public class ParticipantSimParameters implements ParticipantParameters {
192
193     @NotBlank
194     private String myparameter;
195
196     @NotNull
197     @Valid
198     private ParticipantIntermediaryParameters intermediaryParameters;
199   }
200
201 The following example shows the topic parameters and the additional 'myparameter'.
202
203 .. code-block:: bash
204
205   participant:
206     myparameter: my parameter
207     intermediaryParameters:
208       reportingTimeIntervalMs: 120000
209       description: Participant Description
210       participantId: 101c62b3-8918-41b9-a747-d21eb79c6c90
211       clampAutomationCompositionTopics:
212         topicSources:
213           - topic: POLICY-ACRUNTIME-PARTICIPANT
214             servers:
215               - ${topicServer:localhost}
216             topicCommInfrastructure: dmaap
217             fetchTimeout: 15000
218         topicSinks:
219           - topic: POLICY-ACRUNTIME-PARTICIPANT
220             servers:
221               - ${topicServer:localhost}
222             topicCommInfrastructure: dmaap
223       participantSupportedElementTypes:
224         -
225           typeName: org.onap.policy.clamp.acm.MyFirstAutomationCompositionElement
226           typeVersion: 1.0.0
227
228
229 The following example shows the Handler implementation and how could be the implemented the mandatory notifications.
230
231 .. code-block:: java
232
233   @Component
234   @RequiredArgsConstructor
235   public class MyFirstAcElementHandler implements AutomationCompositionElementListener {
236
237     private final ParticipantIntermediaryApi intermediaryApi;
238
239     @Override
240     public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
241             throws PfModelException {
242
243         // TODO deploy process
244
245         if (isDeploySuccess()) {
246             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
247                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
248         } else {
249             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
250                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
251         }
252     }
253
254     @Override
255     public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
256         LOGGER.debug("undeploy call");
257
258         // TODO undeploy process
259
260         if (isUndeploySuccess()) {
261             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
262                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
263                     "Undeployed");
264         } else {
265             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
266                     automationCompositionElementId, DeployState.DEPLOYED, null, StateChangeResult.FAILED,
267                     "Undeploy failed!");
268         }
269     }
270
271     @Override
272     public void lock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
273
274         // TODO lock process
275
276         if (isLockSuccess()) {
277             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
278                     automationCompositionElementId, null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
279         } else {
280             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
281                     automationCompositionElementId, null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
282         }
283     }
284
285     @Override
286     public void unlock(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
287
288         // TODO unlock process
289
290         if (isUnlockSuccess()) {
291             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
292                     automationCompositionElementId, null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
293         } else {
294             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
295                     automationCompositionElementId, null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
296         }
297     }
298
299     @Override
300     public void delete(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
301
302         // TODO delete process
303
304         if (isDeleteSuccess()) {
305             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
306                     automationCompositionElementId, DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
307         } else {
308             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
309                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
310                     "Delete failed!");
311         }
312     }
313
314     @Override
315     public void update(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
316             throws PfModelException {
317
318         // TODO update process
319
320         if (isUpdateSuccess()) {
321             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
322                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
323         } else {
324             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
325                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
326         }
327     }
328
329     @Override
330     public void prime(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList)
331             throws PfModelException {
332
333         // TODO prime process
334
335         if (isPrimeSuccess()) {
336             intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR,
337                     "Primed");
338         } else {
339             intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.FAILED,
340                     "Prime failed!");
341         }
342     }
343
344     @Override
345     public void deprime(UUID compositionId) throws PfModelException {
346
347         // TODO deprime process
348
349         if (isDeprimeSuccess()) {
350             intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR,
351                     "Deprimed");
352         } else {
353             intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.FAILED,
354                     "Deprime failed!");
355         }
356     }
357
358
359