Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Page for general findings around the investigation of the optimal path for CLAMP and Tosca Control Loop Integration.

CLAMP Code Walkthrough videos can be found here

Tosca handling in CLAMP vs Tosca Control Loop - Findings

CSAR from SDC Flow

  1. CSAR contains the DCAE blueprint to be used to deploy to DCAE but also contains a reference to a microservice policy type. CLAMP, on startup, pulls all the policy types and pulls them periodically after that (+pulls the PDP group/subgroup accepted deployment per model). Clamp creates LOOP TEMPLATES from in its database from the blueprints. CLAMP uses the reference from the CSAR to associate the relevant microservice policy type with a loop template. Thus, CLAMP knows which monitoring policy type to use for creation of a Loop instance.
  2. When deploying the SDC notif + CSAR, clamp gets does a query to dcae to get the blueprint ID in the inventory. If it fails CLAMP rollbacks the transactions and abort the SDC notification installation.
  3. During the installation, CLAMP also installs in its DB service information, like UUID VNF associated ... this is used later by the UI to help the user to easily configure the different policies. It supports multiple blueprints per VNF (defined in SDC). The VNFs are retrieved by CLAMP from the SDC notification.
  4. Although there is a comment in "src/main/java/org/onap/policy/clamp/loop/deploy/DcaeDeployParameters.java" saying multiple microservices are not currently possible, +-90% ((smile)) of clamp code "should" support the multi-mircoservices per blueprint. Code was initially written by Nokia to extract multiple microservices from the blueprint BUT Dcae did not and still does not support that. Normally the multi-microservices "should" be come from the new DCAE architecture. (edited - hope that's ok)
  5. The Blueprint Artifact in the CSAR is used to populate the "loop_template" db. These "loop_templates" are used to create instances. All interaction with the database is done using the SpringBoot "@Repository" pattern. Standard boilerplate db interaction is done in most cases with "JpaRepository" (find, save etc).
  6. CLAMP also gets the policy type (based on the policy type id in the Blueprint) from the database. The types are then added to the "loop_element_models" table. The relationship between "loop_element_models" and "policy_models" is recorded in the "loopelementmodels_to_policymodels" table.
  7. The relationship between the loop element models and the loop templates is also recorded in the "looptemplates_to_loopelementmodels" table. In this way, the blueprint templates is associated with a microservice policy.

Loop Creation Flow

When a loop is created in UI or directly in backend:

  1. The loop is saved in the "loops" table.
  2. The microservice policy is created (with a generated name) in the "micro_service_policies" table along with the policy type associated with it and the json representation of the policy type.
  3. The relationship between the microservice policies and the loops is recorded in the "loops_to_microservicepolicies" table. This contains the loop names and the microservice policy names.

Update Loop Flow

It is possible to update a loop that has been created. This allows configuration of the policies attached to the microservice.

  1. Updating a microservice policy or an operational policy can be done in the the UI or by accessing the CLAMP backend directly.
  2. For the microservice policy, you can:
    1. Click on the SVG and a convenience JSON editor will popup and allow properties to be added and removed from the JSON policy configuration template.
    2. Send the JSON configuration of the policy directly to the CLAMP backend endpoint at "/updateMicroservicePolicy".
  3. In both cases, this populates the "configurations_json" field for the microservice in the "micro_service_policies" table.


REST in CLAMP vs REST in Control Loop PoC - Findings

  1. LoopService and MicroservicePolicyService classes resemble our PoC Provider classes, such as Commissioning and Instantiation Provider where java code in regards to CRUD resides
    1.  Examples:

      Code Block
      languagejava
      titleLoopService.getLoop()
      public Loop getLoop(String loopName) {
              return loopsRepository.findById(loopName).orElse(null);
      }


      Code Block
      languagejava
      titleControlLoopInstantiationProvider.GetControlLoops()
      public ControlLoops getControlLoops(String name, String version) throws PfModelException {
          ControlLoops controlLoops = new ControlLoops();
          controlLoops.setControlLoopList(controlLoopProvider.getControlLoops(name, version));
      
          return controlLoops;
      }


    2.  The differences start here, as CLAMP uses the Spring Framework Repository Interfaces to handle database calls, where as PoC is using the code defined in policy-models in regards to Tosca and our own models and JPA classes for ControlLoop related objects. 
      i.e LoopsRepository extends JpaRepository (Spring Framework). Our providers are either created by us or use policy ones i.e. PolicyModelsProvider.
    3.  There seems to be a lot of specific methods for updating the loop templates, such as updateDcaeDeploymentFields() and addOperationalPolicy(). In our case that is handled within the TOSCA service template itself, by mending the template where these objects can be added as nodeTemplates(ControlLoopElements), without having to be specific to a DCAE control loop. Further info in TOSCA handling.

  2.  Actual REST code is handled rather differently. In CLAMP LoopController class serves as a class to introduce Springboot Framework with the "@Controller" annotation, and methods defined in this class are just calling the LoopService Methods. This is to allow these methods to be more easily called by the CAMEL flows using :
    e.g. "<to uri="bean:org.onap.policy.clamp.loop.LoopController?method=getLoop(${header.loopName})"/". In CAMEL the response, logging and error handling occurs, with the code just throwing the exception.
    In our case, our REST code along with annotations, definitions and responses is in our Controllers, which call the provider methods to do the actual interaction. e.g. CommissioningController, which defines the path along with other java.wx.rs inputs.
    1. Examples:

      Code Block
      languagejava
      titleLoopController.getLoop()
      public Loop getLoop(String loopName) {
          return loopService.getLoop(loopName);
      }


      Code Block
      languagexml
      titleCAMEL for getLoop
      collapsetrue
      <get uri="/v2/loop/{loopName}" outType="org.onap.policy.clamp.loop.Loop"
           produces="application/json">
          <route>
              <removeHeaders pattern="*" excludePattern="loopName"/>
              <doTry>
                  <to
                          uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET Loop')"/>
                  <to
                          uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','read')"/>
                  <to
                          uri="bean:org.onap.policy.clamp.loop.LoopController?method=getLoop(${header.loopName})"/>
                  <to
                          uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
                  <doCatch>
                      <exception>java.lang.Exception</exception>
                      <handled>
                          <constant>true</constant>
                      </handled>
                      <to
                              uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
                      <log loggingLevel="ERROR"
                           message="GET Loop request failed for loop: ${header.loopName}, ${exception.stacktrace}"/>
      
                      <setHeader name="CamelHttpResponseCode">
                          <constant>500</constant>
                      </setHeader>
                      <setBody>
                          <simple>GET Loop FAILED</simple>
                      </setBody>
                  </doCatch>
              </doTry>
          </route>
      </get>


      Code Block
      languagejava
      titleJava Code for PoC way of handling REST
      collapsetrue
      @GET
      @Path("/instantiation")
      @ApiOperation(value = "Query details of the requested control loops",
              notes = "Queries details of the requested control loops, returning all control loop details",
              response = ControlLoops.class,
              tags = {
                  "Clamp control loop Instantiation API"
              },
              authorizations = @Authorization(value = AUTHORIZATION_TYPE),
              responseHeaders = {
                      @ResponseHeader(
                              name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
                                      response = String.class),
                      @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
                                      response = String.class),
                      @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
                                      response = String.class),
                      @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
                                      response = UUID.class)},
              extensions = {
                      @Extension(
                              name = EXTENSION_NAME,
                              properties = {
                                      @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
                                      @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
                          }
                      )
                  }
          )
      @ApiResponses(
              value = {
                  @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
                  @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
                  @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
              }
          )
      // @formatter:on
      public Response query(
              @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
              @ApiParam(value = "Control Loop definition name", required = true) @QueryParam("name") String name,
              @ApiParam(value = "Control Loop definition version",
                      required = true) @QueryParam("version") String version) {
      
          try {
              ControlLoops response = provider.getControlLoops(name, version);
              return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response)
                      .build();
      
          } catch (PfModelRuntimeException | PfModelException e) {
              LOGGER.warn("commisssioning of control loop failed", e);
              return createInstantiationErrorResponse(e, requestId);
          }
      
      }


    2. My knowledge on Spring is limited. Overall it seems more of a preference. Switching PoC way to handle REST to Spring/CAMEL as is in CLAMP should not be a massive hurdle, unless if Spring can only handle database queries which are defined by Spring Interfaces, and we cannot create "@Controller" for our provider(Service) code which uses our own JPA code for interacting with the DB
    3. I also want to mention that Spring/Camel is handling the DB transactions for US. Each time an endpoint is hit, the transaction is automatically opened, you can therefore (with specific annotations) abort, open new transac within the first one, control the transac if needed ....etc ... When no exception is raised the commit is done when the call ends. I see SpringBoot as an enterprise java Container that comes with JPA/JTA/Beans/Rest +..... functionalities out of the box (like JBOSS).