More documentation of specific actor types
[policy/parent.git] / docs / development / actors / overview.rst
1 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
2
3 .. _actors-overview-label:
4
5 #####################
6 Actor Design Overview
7 #####################
8
9 .. contents::
10
11 Intro
12 #####
13
14 An actor/operation is any ONAP component that an Operational Policy can use to control
15 a VNF/VM/etc. during execution of a control loop operational policy when a Control Loop
16 Event is triggered.
17
18 .. image:: topview.png
19
20 An Actor Service object contains one or more Actor objects, which are found and created
21 using *ServiceLoader*.  Each Actor object, in turn, creates one or more Operator objects.
22 All of these components, the Actor Service, the Actor, and the Operator are typically
23 singletons that are created once, at start-up (or on the first request).
24 The Actor Service includes several methods, *configure()*, *start()*, and *stop()*,
25 which are cascaded to the Actors and then to the Operators.
26
27 Operation objects, on the other hand, are not singletons; a new Operation object is
28 created for each operation that an application wishes to perform. For instance, if an
29 application wishes to use the "SO" Actor to add two new modules, then two separate
30 Operation objects would be created, one for each module.
31
32 Actors are configured by invoking the Actor Service *configure()* method, passing it
33 a set of properties.  The *configure()* method extracts the properties that are relevant
34 to each Actor and passes them to the Actor's *configure()* method.  Similarly, the
35 Actor's *configure()* method extracts the properties that are relevant
36 to each Operator and passes them to the Operator's *configure()* method.  Note:
37 Actors typically extract "default" properties from their respective property sets
38 and include those when invoking each Operator's *configure()* method.
39
40 Once the Actor Service has been configured, it can be started via *start()*.  It will
41 then continue to run until no longer needed, at which point *stop()* can be invoked.
42
43 Note: it is possible to create separate instances of an Actor Service, each with its
44 own set of properties.  In that case, each Actor Service will get its own instances of
45 Actors and Operators.
46
47 Components
48 ##########
49
50 This section describes things to consider when creating a new Actor/Operator.
51
52 Actor
53 *****
54
55 - The constructor should use addOperator() to add operators
56 - By convention, the name of the actor is specified by a static field, "NAME"
57 - An actor is registered via the Java ServiceLoader by including its jar on the
58   classpath and adding its class name to this file, typically contained within the jar:
59
60       onap.policy.controlloop.actorServiceProvider.spi
61
62 - Actor loading is ordered, so that those having a lower (i.e., earlier) sequence number
63   are loaded first.  If a later actor has the same name as one that has already been
64   loaded, a warning will be generated and the later actor discarded.  This makes it
65   possible for an organization to override an actor implementation
66 - An implementation for a specific Actor will typically be derived from
67   *HttpActor* or *BidirectionalTopicActor*, depending whether it is HTTP/REST-based
68   or DMaaP-topic-based.  These super classes provide most of the functionality needed
69   to configure the operators, extracting operator-specific properties and adding
70   default, actor-level properties
71
72 Operator
73 ********
74
75 - Typically, developers don’t have to implement any Operator classes; they just use
76   *HttpOperator* or *BidirectionalTopicOperator*
77
78 Operation
79 *********
80
81 - Most operations require guard checks to be performed first. Thus, at a minimum, they
82   should override *startPreprocessorAsync()* and have it invoke *startGuardAsync()*
83 - In addition, if the operation depends on data being previously gathered and placed
84   into the context, then it should override *startPreprocessorAsync()* and have it
85   invoke *obtain()*. Note: *obtain()*
86   and the guard can be performed in parallel by using the *allOf()* method.  If the
87   guard
88   happens to depend on the same data, then it will block until the data is available,
89   and then continue; the invoker need not deal with the dependency
90 - Subclasses will typically derive from *HttpOperation* or *BidirectionalTopicOperation*,
91   though if neither of those suffice, then they can extend *OperationPartial*, or
92   even just implement a raw *Operation*.  *OperationPartial* is the super class of
93   *HttpOperation* and *BidirectionalTopicOperation* and provides most of the methods
94   used by the Operation subclasses, including a number of utility methods (e.g.,
95   cancellable *allOf*)
96 - Operation subclasses should be written in a way so-as to avoid any blocking I/O.  If
97   this proves too difficult, then the implementation should override *doOperation()*
98   instead of *startOperationAsync()*
99 - Operations return a "future" when *start()* is invoked.  Typically, if the "future" is
100   canceled, then any outstanding operation should be canceled.  For instance, HTTP
101   connections should be closed without waiting for a response
102 - If an operation sets the outcome to "FAILURE", it will be automatically retried; other
103   failure types are not retried
104
105 ControlLoopParams
106 *****************
107
108 - Identifies the operation to be performed
109 - Includes timeout and retry information, though the actors typically provide default
110   values if they are not specified in the parameters
111 - Includes the event "context"
112 - Includes “Policy” fields (e.g., "actor" and "operation")
113
114 Context (aka, Event Context)
115 ****************************
116
117 - Includes:
118
119     - the original onset event
120     - enrichment data associated with the event
121     - results of A&AI queries
122
123 XxxParams and XxxConfig
124 ***********************
125
126 - XxxParams objects are POJOs into which the property Maps are decoded when configuring
127   actors or operators
128 - XxxConfig objects contain a single Operator's (or Actor's) configuration information,
129   based on what was in the XxxParams.  For instance, the HttpConfig contains a reference
130   to the HttpClient that is used to perform HTTP
131   operations, while the associated HttpParams just contains the name of the HttpClient.
132   XxxConfig objects are
133   shared by all operations created by a single Operator.  As a result, it should not
134   contain any data associated with an individual operation; such data should be stored
135   within the Operation object, itself
136
137 Junit tests
138 ***********
139
140 - Operation Tests may choose to subclass from *BasicHttpOperation*, which provides some
141   supporting utilities and mock objects
142 - Should include a test to verify that the Actor, and possibly each Operator, can be
143   retrieved via an Actor Service
144 - Tests with an actual REST server are performed within *HttpOperationTest*, so need not
145   be repeated in subclasses. Instead, they can catch the callback to the *get()*,
146   *post()*, etc., methods and pass the rawResponse to it there.  That being said, a
147   number of actors spin up a simulator to verify end-to-end request/response processing
148
149 Clients (e.g., drools-applications)
150 ***********************************
151
152 - When using callbacks, a client may want to use the *isFor()* method to verify that the
153   outcome is for the desired operation, as callbacks are invoked with the outcome of all
154   operations performed, including any preprocessor steps
155
156 Flow of operation
157 #################
158
159 - PDP:
160
161   - Populates a *ControlLoopParams* using *ControlLoopParams.builder()*
162   - Invokes *start()* on the *ControlLoopParams*
163
164 - ControlLoopParams:
165
166   - Finds the actor/operator
167   - Uses it to invoke *buildOperation()*
168   - Invokes *start()* on the Operation
169
170 - Operation:
171
172   - *start()* invokes *startPreprocessorAsync()* and then *startOperationAsync()*
173   - Exceptions that occur while **constructing** the operation pipeline propagate back
174     to the client that invoked *start()*
175   - Exceptions that occur while **executing** the operation pipeline are caught and
176     turned into an *OperationOutcome* whose result is FAILURE_EXCEPTION.  In addition,
177     the "start" callback (i.e., specified via the *ControlLoopParams*) will be invoked,
178     if it hasn't been invoked yet, and then the "complete" callback will be invoked
179   - By default, *startPreprocessorAsync()* does nothing, thus most subclasses will override it to:
180
181     - Do any A&AI query that is needed (beyond enrichment, which is already available in
182       the *Context*)
183     - Use *Context obtain()* to request the data asynchronously
184     - Invoke *startGuardAsync()*
185
186   - By default, *startGuardAsync()* will simply perform a guard check, passing it the
187     "standard" payload
188   - Subclasses may override *makeGuardPayload()* to add extra fields to the payload
189     (e.g., some SO operations add the VF count)
190   - If any preprocessing step fails, then the "start" and "complete" callbacks will be
191     invoked to indicate a failure of the operation as a whole. Otherwise, the flow will
192     continue on to *startOperationAsync()*, after the "start" callback is invoked
193   - *StartOperationAsync()* will perform whatever needs to be done to start the operation
194   - Once it completes, the "complete" callback will be invoked with the outcome of the
195     operation.  *StartOperationAsync()* should not invoke the callback, as that is
196     handled automatically by *OperationPartial*, which is the superclass of most
197     Operations