Document overview of new actor model 67/107367/2
authorJim Hahn <jrh3@att.com>
Fri, 8 May 2020 19:40:54 +0000 (15:40 -0400)
committerJim Hahn <jrh3@att.com>
Fri, 8 May 2020 19:41:39 +0000 (15:41 -0400)
This is the overview only; any documentation for specifics actors
in subsequent reviews.

Issue-ID: POLICY-2500
Change-Id: I899e161561ffea90c93abf85731c2f62310d64f0
Signed-off-by: Jim Hahn <jrh3@att.com>
docs/development/actors/actors.rst
docs/development/actors/overview.rst [new file with mode: 0644]
docs/development/actors/topview.png [new file with mode: 0644]
docs/development/actors/topview.pptx [new file with mode: 0644]

index 7005489..160f2cc 100644 (file)
@@ -6,6 +6,7 @@ Policy Platform Actor Development Guidelines
 --------------------------------------------
 
 .. toctree::
-   :maxdepth: 1
+    :maxdepth: 1
 
-   cds/cds.rst
+    overview.rst
+    cds/cds.rst
diff --git a/docs/development/actors/overview.rst b/docs/development/actors/overview.rst
new file mode 100644 (file)
index 0000000..716f4f2
--- /dev/null
@@ -0,0 +1,187 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+
+.. _actors-overview-label:
+
+#####################
+Actor Design Overview
+#####################
+
+.. contents::
+
+Intro
+#####
+
+An actor/operation is any ONAP component that an Operational Policy can use to control
+a VNF/VM/etc. during execution of a control loop operational policy when a Control Loop
+Event is triggered.
+
+.. image:: topview.png
+
+An Actor Service object contains one or more Actor objects, which are found and created
+using *ServiceLoader*.  Each Actor object, in turn, creates one or more Operator objects.
+All of these components, the Actor Service, the Actor, and the Operator are typically
+singletons that are created once, at start-up (or on the first request).
+The Actor Service includes several methods, *configure()*, *start()*, and *stop()*,
+which are cascaded to the Actors and then to the Operators.
+
+Operation objects, on the other hand, are not singletons; a new Operation object is
+created for each operation that an application wishes to perform. For instance, if an
+application wishes to use the "SO" Actor to add two new modules, then two separate
+Operation objects would be created, one for each module.
+
+Actors are configured by invoking the Actor Service *configure()* method, passing it
+a set of properties.  The *configure()* method extracts the properties that are relevant
+to each Actor and passes them to the Actor's *configure()* method.  Similarly, the
+Actor's *configure()* method extracts the properties that are relevant
+to each Operator and passes them to the Operator's *configure()* method.  Note:
+Actors typically extract "default" properties from their respective property sets
+and include those when invoking each Operator's *configure()* method.
+
+Once the Actor Service has been configured, it can be started via *start()*.  It will
+then continue to run until no longer needed, at which point *stop()* can be invoked.
+
+Note: it is possible to create separate instances of an Actor Service, each with its
+own set of properties.  In that case, each Actor Service will get its own instances of
+Actors and Operators.
+
+Components
+##########
+
+This section describes things to consider when creating a new Actor/Operator.
+
+Actor
+*****
+
+- The constructor should use addOperator() to add operators
+- By convention, the name of the actor is specified by a static field, "NAME"
+- An actor is registered via the Java ServiceLoader by including its jar on the
+  classpath and adding its class name to this file, typically contained within the jar:
+
+      onap.policy.controlloop.actorServiceProvider.spi
+
+- Actor loading is ordered, so that those having a lower (i.e., earlier) sequence number
+  are loaded first.  If a later actor has the same name as one that has already been
+  loaded, a warning will be generated and the later actor discarded.  This makes it
+  possible for an organization to override an actor implementation
+
+Operator
+********
+
+- Typically, developers don’t have to implement any Operator classes; they just use
+  *HttpOperator* or *BidirectionalTopicOperator*
+
+Operation
+*********
+
+- Most operations require guard checks to be performed first. Thus, at a minimum, they
+  should override *startPreprocessorAsync()* and have it invoke *startGuardAsync()*
+- In addition, if the operation depends on data being previously gathered and placed
+  into the context, then it should override *startPreprocessorAsync()* and have it
+  invoke *obtain()*. Note: *obtain()*
+  and the guard can be performed in parallel by using the *allOf()* method.  If the
+  guard
+  happens to depend on the same data, then it will block until the data is available,
+  and then continue; the invoker need not deal with the dependency
+- Subclasses will typically derive from *HttpOperation* or *BidirectionalTopicOperation*,
+  though if neither of those suffice, then they can extend *OperationPartial*, or
+  even just implement a raw *Operation*
+- Operation subclasses should be written in a way so-as to avoid any blocking I/O
+- Operations return a "future" when *start()* is invoked.  Typically, if the "future" is
+  canceled, then any outstanding operation should be canceled.  For instance, HTTP
+  connections should be closed without waiting for a response
+- If an operation sets the outcome to "FAILURE", it will be automatically retried; other
+  failure types are not retried
+
+ControlLoopParams
+*****************
+
+- Identifies the operation to be performed
+- Includes timeout and retry information, though the actors typically provide default
+  values if they are not specified in the parameters
+- Includes the event "context"
+- Includes “Policy” fields (e.g., "actor" and "operation")
+
+Context (aka, Event Context)
+****************************
+
+- Includes:
+
+    - the original onset event
+    - enrichment data associated with the event
+    - results of A&AI queries
+
+XxxParams and XxxConfig
+***********************
+
+- XxxParams objects are POJOs into which the property Maps are decoded when configuring
+  actors or operators
+- XxxConfig objects contain a single Operator's (or Actor's) configuration information,
+  based on what was in the XxxParams.  For instance, the HttpConfig contains a reference
+  to the HttpClient that is used to perform HTTP
+  operations, while the associated HttpParams just contains the name of the HttpClient.
+  XxxConfig objects are
+  shared by all operations created by a single Operator.  As a result, it should not
+  contain any data associated with an individual operation; such data should be stored
+  within the operation object, itself
+
+Junit tests
+***********
+
+- Operation Tests may choose to subclass from *BasicHttpOperation*, which provides some
+  supporting utilities and mock objects
+- Should include a test to verify that the Actor, and possibly each Operator, can be
+  retrieved via an Actor Service
+- Tests with an actual REST server are performed within *HttpOperationTest*, so need not
+  be repeated in subclasses. Instead, they can catch the callback to the *get()*,
+  *post()*, etc., methods and pass the rawResponse to it there.  That being said, a
+  number of actors spin up a simulator to verify end-to-end request/response processing
+
+Clients (e.g., drools-applications)
+***********************************
+
+- When using callbacks, a client may want to use the *isFor()* method to verify that the
+  outcome is for the desired operation, as callbacks are invoked with the outcome of all
+  operations performed, including any preprocessor steps
+
+Flow of operation
+#################
+
+- PDP:
+
+  - Populates a *ControlLoopParams* using *ControlLoopParams.builder()*
+  - Invokes *start()* on the *ControlLoopParams*
+
+- ControlLoopParams:
+
+  - Finds the actor/operator
+  - Uses it to invoke *buildOperation()*
+  - Invokes *start()* on the Operation
+
+- Operation:
+
+  - *start()* invokes *startPreprocessorAsync()* and then *startOperationAsync()*
+  - Exceptions that occur while **constructing** the operation pipeline propagate back
+    to the client that invoked *start()*
+  - Exceptions that occur while **executing** the operation pipeline are caught and
+    turned into an *OperationOutcome* whose result is FAILURE_EXCEPTION.  In addition,
+    the "start" callback (i.e., specified via the *ControlLoopParams*) will be invoked,
+    if it hasn't been invoked yet, and then the "complete" callback will be invoked
+  - By default, *startPreprocessorAsync()* does nothing, thus most subclasses will override it to:
+
+    - Do any A&AI query that is needed (beyond enrichment, which is already available in
+      the *Context*)
+    - Use *Context obtain()* to request the data asynchronously
+    - Invoke *startGuardAsync()*
+
+  - By default, *startGuardAsync()* will simply perform a guard check, passing it the
+    "standard" payload
+  - Subclasses may override *makeGuardPayload()* to add extra fields to the payload
+    (e.g., some SO operations add the VF count)
+  - If any preprocessing step fails, then the "start" & "complete" callbacks will be
+    invoked to indicate a failure of the operation as a whole. Otherwise, the flow will
+    continue on to *startOperationAsync()*, after the "start" callback is invoked
+  - *StartOperationAsync()* will perform whatever needs to be done to start the operation
+  - Once it completes, the "complete" callback will be invoked with the outcome of the
+    operation.  *StartOperationAsync()* should not invoke the callback, as that is
+    handled automatically by *OperationPartial*, which is the superclass of most
+    Operations
diff --git a/docs/development/actors/topview.png b/docs/development/actors/topview.png
new file mode 100644 (file)
index 0000000..a7e5b16
Binary files /dev/null and b/docs/development/actors/topview.png differ
diff --git a/docs/development/actors/topview.pptx b/docs/development/actors/topview.pptx
new file mode 100644 (file)
index 0000000..16ff224
Binary files /dev/null and b/docs/development/actors/topview.pptx differ