#!/bin/bash ############################################################################# # # Copyright (c) 2017 AT&T Intellectual Property. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################# # prepare a curl command # parameters: URL METHOD CURLOPTIONS EXTRA_HEADERS_AS_A_STRING AUTH_AS_USER:PASS DATA assemble_curl_command() { local URL="$1" local METHOD="$2" local CURLOPTIONS="$3" local EXTRA_HEADERS="$4" local AUTH="$5" local DATA="$6" local CMD='' if [ ! -z "$METHOD" ]; then CMD="curl $CURLOPTIONS $METHOD" else CMD="curl $CURLOPTIONS -X GET" fi if [ ! -z "$EXTRA_HEADERS" ]; then CMD="$CMD $EXTRA_HEADERS" fi if [ ! -z "$AUTH" ]; then CMD="$CMD $AUTH" fi if [ ! -z "$DATA" ]; then CMD="$CMD $DATA" fi CMD="$CMD $URL" echo "$CMD" } # Make a rest API call # parameters: URL METHOD expected_response_code EXTRA_HEADERS_AS_A_STRING AUTH_AS_USER:PASS DATA call_api_for_response_code() { local CURLOPTIONS='-kIso /dev/null -w "%{http_code}"' read -r CMDF <<-END $(assemble_curl_command "$1" "$2" "$CURLOPTIONS" "$4" "$5" "$6") END eval "$CMDF"; } call_api_for_response_body() { local CURLOPTIONS='-ksb' read -r CMDF <<-END $(assemble_curl_command "$1" "$2" "$CURLOPTIONS" "$4" "$5" "$6") END eval "$CMDF" } call_api_for_response_header() { local CURLOPTIONS='-ks -o /dev/null -D -' read -r CMDF <<-END $(assemble_curl_command "$1" "$2" "$CURLOPTIONS" "$4" "$5" "$6") END eval "$CMDF" } call_api_for_verbose() { local CURLOPTIONS='-kIv' read -r CMDF <<-END $(assemble_curl_command "$1" "$2" "$CURLOPTIONS" "$4" "$5" "$6") END eval "$CMDF" #local TFILE=$(mktemp /tmp/curlcmd.XXXXXXXXX) #echo $CMD > $TFILE #eval $(cat $TFILE) #rm -f $TFILE } # Wait till a web service API return specified response code # parameters: URL METHOD EXPECTED_RESP_CODE EXTRA_HEADERS_AS_A_STRING AUTH_AS_USER:PASS DATA wait_for_api() { local RESP="$3" local ACTUALRESP ACTUALRESP=$(call_api_for_response_code "$1" "$2" "$3" "$4" "$5" "$6") while [ "$ACTUALRESP" != "$RESP" ]; do echo "RESP CODE $ACTUALRESP, not as expected RESP CODE $RESP @ $(date)." sleep 30 ACTUALRESP=$(call_api_for_response_code "$1" "$2" "$3" "$4" "$5" "$6") done echo "RESP CODE $ACTUALRESP, matches with expected RESP CODE $RESP." } # Wait till a TCP port is open # parameters: HOST PORT wait_for_tcp_port() { local DEST="$1" local PORT="$2" while ! nc -z -w 1 "$DEST" "$PORT"; do sleep 4 echo '.' done } wait_for_aai_ready() { # wait till A&AI up and ready local AAIHOST AAIHOST=$(cat /opt/config/aai1_ip_addr.txt) local AAIURL="https://$AAIHOST:8443/aai/v11/examples/cloud-regions" local AAIMETHOD='-X GET' local AAIRESP='200' local AAIHEADERS='-H "X-FromAppId: AAI-Temp-Tool" -H "X-TransactionId: AAI-Temp-Tool" -H "Real-Time: true" -H "Content-Type: application/json" -H "Accept: application/json"' local AAIAUTH='-u AAI:AAI' local AAIDATA='' echo "===> Waiting for A&AI to get ready for getting $AAIRESP from $AAIURL @ $(date)" wait_for_api "$AAIURL" "$AAIMETHOD" "$AAIRESP" "$AAIHEADERS" "$AAIAUTH" "$AAIDATA" echo "===> A&AI ready @ $(date)" } wait_for_multicloud_ready() { # wait till MultiCloud up and ready local MCHOST MCHOST=$(cat /opt/config/openo_ip_addr.txt) local MCURL="http://$MCHOST:9005/api/multicloud-titanium_cloud/v0/swagger.json" local MCMETHOD='-X GET' local MCRESP='200' local MCHEADERS='-H "Real-Time: true" -H "Content-Type: application/json" -H "Accept: application/json"' local MCAUTH='' local MCDATA='' echo "===> Waiting for MultiCloud to get ready for getting $MCRESP from $MCURL @ $(date)" wait_for_api "$MCURL" "$MCMETHOD" "$MCRESP" "$MCHEADERS" "$MCAUTH" "$MCDATA" echo "===> MultiCloud ready @ $(date)" } register_multicloud_pod25dns_with_aai() { # Register MultiCloud with A&AI local CLOUD_OWNER='pod25dns' local CLOUD_VERSION='titanium_cloud' local CLOUD_REGION local CLOUD_ENV local CLOUD_IDENTITY_URL local DNSAAS_SERVICE_URL local DNSAAS_USERNAME='demo' local DNSAAS_PASSWORD='onapdemo' CLOUD_REGION="$(cat /opt/config/dnsaas_region.txt)" CLOUD_ENV="$(cat /opt/config/cloud_env.txt)" MCIP="$(cat /opt/config/openo_ip_addr.txt)" CLOUD_IDENTITY_URL="http://${MCIP}/api/multicloud-titanium_cloud/v0/${CLOUD_OWNER}_${CLOUD_REGION}/identity/v2.0" local RESPCODE DNSAAS_SERVICE_URL="$(cat /opt/config/dnsaas_keystone_url.txt)" # a tenant of the same name must be set up on the Deisgnate providing OpenStack DNSAAS_TENANT_NAME="$(cat /opt/config/dnsaas_tenant_name.txt)" cat >"/tmp/${CLOUD_OWNER}_${CLOUD_REGION}.json" <"/tmp/${CLOUD_OWNER}_${CLOUD_REGION}.json" <
ONAP Control Loop Policy v1.0.0

A control loop policy is a YAML specification for creating and chaining policies for ControlLoop.

Features of ONAP Control Loop Policy v1.0.0:

* A single DCAE Closed Loop Event is the trigger for the overall Control Loop Policy
* APPC is the only Actor that Policy will interact with. The operations available are: RESTART, REBUILD, MIGRATE.
* An overall timeout for the Control Loop Policy must be provided
* The Control Loop Policy can contain zero or more Operational Policies each chained together via outcomes of each policy.
* If there are zero Operational Policies, i.e. no automated action is to be taken, then the policy is an Open Loop policy.
* Operational Policies can have retries and timeout's given to control how they are processed.

This SDK helps build the YAML specification for ONAP Control Loop Policy v1.0.0.

# Create Builder Object

To begin with, the ControlLoopPolicyBuilder.Factory class has static methods that one should use to begin building a Control Loop Policy. It will return a [ControlLoopPolicyBuilder object](src/main/java/org/onap/policy/controlloop/policy/builder/ControlLoopPolicyBuilder.java) that can then be used to continue to build and define the Control Loop Policy.

```java
		ControlLoopPolicyBuilder builder = ControlLoopPolicyBuilder.Factory.buildControlLoop(
				UUID.randomUUID().toString(), 
				2400, 
				new Resource("sampleResource", ResourceType.VF),
				new Service("sampleService")
				);
```

# Define the Trigger Policy

After the name of the Control Loop and the resource and services have been defined, the next step would be to define the Operation Policy that is first to respond to an incoming DCAE Closed Loop Event. Use the setTriggerPolicy() method to do so.

```java
		Policy triggerPolicy = builder.setTriggerPolicy(
				"Restart the VM", 
				"Upon getting the trigger event, restart the VM", 
				Actor.APPC, 
				Target.VM, 
				"Restart", 
				2, 
				300);
```

# Chain Operational Policies Together Using Operational Results

Operational Policies are chained together using the results of each Operational Policy. The results are defined in [PolicyResult.java](src/main/java/org/onap/policy/controlloop/policy/PolicyResult.java). To create an Operational Policy that is tied to the result of another, use the 
setPolicyForPolicyResult() method.

```java
		Policy onRestartFailurePolicy = builder.setPolicyForPolicyResult(
				"Rebuild VM", 
				"If the restart fails, rebuild it.", 
				Actor.APPC, 
				Target.VM, 
				"Rebuild", 
				1, 
				600, 
				triggerPolicy.id, 
				PolicyResult.FAILURE,
				PolicyResult.FAILURE_RETRIES,
				PolicyResult.FAILURE_TIMEOUT);
```

An Operational Policy MUST have place to go for every one of its results. By default, each result type goes to a Final Result. Optionally, using the setPolicyForPolicyResult() method is what allows the chaining of policies. Be aware of creating loops and set the overall Control Loop timeout to reasonable value. All paths MUST lead to a Final Result.

# Build the YAML Specification

When finished defining the Policies, build the specification and analyze the [Results.java](src/main/java/org/onap/policy/controlloop/policy/builder/Results.java)

```java
		Results results = builder.buildSpecification();
		if (results.isValid()) {
			System.out.println(results.getSpecification());
		} else {
			System.err.println("Builder failed");
			for (Message message : results.getMessages()) {
				System.err.println(message.getMessage());
			}
		}
```


# Use the YAML Specification to call the Create Policy API

Now that you have a valid YAML specification, call the createPolicy API via the ONAP Policy Platform API.

# YAML Specification

The YAML specification has 2 sections to it: [controlLoop](#controlloop-object) and [policies](#policies-array). The [controlLoop section](#controlloop-object) section is simply a header defining the Control Loop Policy, what services its for, which resource its for, or if its for a pnf, the overall timeout, and which Operational Policy is triggered upon receiving the event. The [policies section](#policies-array) is simply an array of [Policy Objects](#policy-object).

## controlLoop Object

| Field Name      | Type          | Required   | Description  |
| -------------   |:-------------:| -----------| ------------:|
| controlLoopName | string        | required | Unique ID for the control Loop |
| version         | string        | required | Value for this release if 1.0.0 |
| services        | array of [service](#service-object) objects | optional | Zero or more services associated with this Control Loop |
| resources        | array of [resource](#resource-object) object | required (If NOT a pnf control loop) | The resource's associated with this Control Loop. |
| pnf             | [pnf](#pnf-object) object | required (If NOT a resource control loop) | The physical network function associated with this Control Loop. |
| trigger_policy  | string     | required | Either this is the ID of an Operation Policy (see policy object), or "Final_OpenLoop" indicating an Open Loop |
| timeout         | int | required | This is the overall timeout for the Control Loop Policy. It can be 0 for an Open Loop, but otherwise should total more than the timeouts specified in any Operational Policies |

### resource Object

This object was derived via SDC Catalog API and SDC Data Dictionary (POC) in an attempt to use common naming conventions.

| Field Name      | Type          | Required   | Description  |
| -------------   |:-------------:| -----------| ------------:|
| resourceInvariantUUID | string - UUID | optional | via SDC, the unique ID for the resource version |
| resourceName | string | required if NO resourceUUID available | Name of the resource, ideally from SDC catalog. But if not available, use well-known name. |
| resourceType | string | optional | Use values defined by SDC: VF, VFC, VL, CP. |
| resourceUUID | string - UUID | required IF available, else populate resourceName | Unique ID for the resource as assigned via SDC.
| resourceVersion | string | optional | string version of the resource via SDC catalog

SDC catalog is not fully available and resources have not been defined yet, use resourceName. Eg. vFW

### service Object

This object was derived via SDC Catalog API and SDC Data Dictionary (POC) in an attempt to use common naming conventions.

| Field Name      | Type          | Required   | Description  |
| -------------   |:-------------:| -----------| ------------:|
| serviceInvariantUUID | string - UUID | optional | via SDC catalog, the unique ID for the service version |
| serviceName | string | required if NO serviceUUID available | Name of the service, ideally from SDC catalog. But if not available, use well-known name. |
| serviceUUID | string - UUID | required IF available, else populate serviceName | Unique ID fort he service as assigned via SDC
| serviceVersion | string | optional | string version of the service via SDC catalog
    
SDC catalog is not fully available and some services have not been defined yet, use serviceName. Eg. vLB.

### pnf Object

This object is used for a physical network function. Expect this object to change in the future when ONAP Policy fully integrates with A&AI.

| Field Name      | Type          | Required   | Description  |
| -------------   |:-------------:| -----------| ------------:|
| PNFName         | string        | required   | Name of the PNF. Should be supplied via A&AI. If not available use a well-known name. |
| PNFType         | string        | optional   | Type of PNF if available. |