Files for vFW DT Use case tutorial 15/89515/1
authorLukasz Rajewski <lukasz.rajewski@orange.com>
Tue, 4 Jun 2019 11:19:49 +0000 (13:19 +0200)
committerBrian Freeman <bf1936@att.com>
Thu, 6 Jun 2019 13:31:56 +0000 (13:31 +0000)
Change-Id: Ie86576ba685ae446c53692e826e2fb83a628bf07
Signed-off-by: Lukasz Rajewski <lukasz.rajewski@orange.com>
Issue-ID: INT-751
(cherry picked from commit d2fd9916127de68e79ace6acd4eedf68873b4af1)

13 files changed:
tutorials/vFWDT/playbooks/vfw-sink/latest/ansible/distributetrafficcheck/site.yml [new file with mode: 0644]
tutorials/vFWDT/playbooks/vpgn/latest/ansible/distributetraffic/site.yml [new file with mode: 0644]
tutorials/vFWDT/playbooks/vpgn/latest/ansible/distributetrafficcheck/site.yml [new file with mode: 0644]
tutorials/vFWDT/preloads/vfw-1-preload.json [new file with mode: 0644]
tutorials/vFWDT/preloads/vfw-2-preload.json [new file with mode: 0644]
tutorials/vFWDT/preloads/vpkg-preload.json [new file with mode: 0644]
tutorials/vFWDT/workflow/README.md [new file with mode: 0644]
tutorials/vFWDT/workflow/requirements.txt [new file with mode: 0644]
tutorials/vFWDT/workflow/templates/appcDmaapLcm.json [new file with mode: 0644]
tutorials/vFWDT/workflow/templates/appcRestconfLcm.json [new file with mode: 0644]
tutorials/vFWDT/workflow/templates/hasRequest.json [new file with mode: 0644]
tutorials/vFWDT/workflow/templates/osdfRequest.json [new file with mode: 0644]
tutorials/vFWDT/workflow/workflow.py [new file with mode: 0644]

diff --git a/tutorials/vFWDT/playbooks/vfw-sink/latest/ansible/distributetrafficcheck/site.yml b/tutorials/vFWDT/playbooks/vfw-sink/latest/ansible/distributetrafficcheck/site.yml
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tutorials/vFWDT/playbooks/vpgn/latest/ansible/distributetraffic/site.yml b/tutorials/vFWDT/playbooks/vpgn/latest/ansible/distributetraffic/site.yml
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tutorials/vFWDT/playbooks/vpgn/latest/ansible/distributetrafficcheck/site.yml b/tutorials/vFWDT/playbooks/vpgn/latest/ansible/distributetrafficcheck/site.yml
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tutorials/vFWDT/preloads/vfw-1-preload.json b/tutorials/vFWDT/preloads/vfw-1-preload.json
new file mode 100644 (file)
index 0000000..be42a3b
--- /dev/null
@@ -0,0 +1,141 @@
+{
+     "input": {
+          "request-information": {
+               "notification-url": "openecomp.org",
+               "order-number": "1",
+               "order-version": "1",
+               "request-action": "PreloadVNFRequest",
+               "request-id": "robot12"
+          },
+          "sdnc-request-header": {
+               "svc-action": "reserve",
+               "svc-notification-url": "http:\/\/openecomp.org:8080\/adapters\/rest\/SDNCNotify",
+               "svc-request-id": "robot12"
+          },
+          "vnf-topology-information": {
+               "vnf-assignments": {
+                    "availability-zones": [],
+                    "vnf-networks": [],
+                    "vnf-vms": []
+               },
+               "vnf-parameters":
+               [{
+                         "vnf-parameter-name": "unprotected_private_net_id",
+                         "vnf-parameter-value": "unprotected_net_dt"
+                    }, {
+                         "vnf-parameter-name": "unprotected_private_subnet_id",
+                         "vnf-parameter-value": "unprotected_subnet_dt"
+                    }, {
+                         "vnf-parameter-name": "unprotected_private_net_cidr",
+                         "vnf-parameter-value": "192.168.10.0/24"
+                    }, {
+                         "vnf-parameter-name": "protected_private_net_id",
+                         "vnf-parameter-value": "protected_net_dt"
+                    }, {
+                         "vnf-parameter-name": "protected_private_net_cidr",
+                         "vnf-parameter-value": "192.168.20.0/24"
+                    }, {
+                         "vnf-parameter-name": "protected_private_subnet_id",
+                         "vnf-parameter-value": "protected_subnet_dt"
+                    }, {
+                         "vnf-parameter-name": "key_name",
+                         "vnf-parameter-value": "vfw_key"
+                    }, {
+                         "vnf-parameter-name": "cloud_env",
+                         "vnf-parameter-value": "openstack"
+                    }, {
+                         "vnf-parameter-name": "vsn_name_0",
+                         "vnf-parameter-value": "vfw-vsn-1-dt"
+                    }, {
+                         "vnf-parameter-name": "onap_private_net_id",
+                         "vnf-parameter-value": "oam_onap_y3id"
+                    }, {
+                         "vnf-parameter-name": "onap_private_subnet_id",
+                         "vnf-parameter-value": "oam_onap_y3id"
+                    }, {
+                         "vnf-parameter-name": "onap_private_net_cidr",
+                         "vnf-parameter-value": "10.0.0.0/16"
+                    }, {
+                         "vnf-parameter-name": "ext_private_net_id",
+                         "vnf-parameter-value": "onap_oam_ext"
+                    }, {
+                         "vnf-parameter-name": "ext_private_subnet_id",
+                         "vnf-parameter-value": "onap_oam_ext_sub"
+                    }, {
+                         "vnf-parameter-name": "ext_private_net_cidr",
+                         "vnf-parameter-value": "10.100.0.0/16"
+                    }, {
+                         "vnf-parameter-name": "nexus_artifact_repo",
+                         "vnf-parameter-value": "https://nexus.onap.org"
+                    }, {
+                         "vnf-parameter-name": "vfw_name_0",
+                         "vnf-parameter-value": "vfw-vfw-1-dt"
+                    }, {
+                         "vnf-parameter-name": "dcae_collector_port",
+                         "vnf-parameter-value": "8080"
+                    }, {
+                         "vnf-parameter-name": "public_net_id",
+                         "vnf-parameter-value": "external"
+                    }, {
+                         "vnf-parameter-name": "image_name",
+                         "vnf-parameter-value": "ubuntu-14-04-cloud-amd64"
+                    }, {
+                         "vnf-parameter-name": "flavor_name",
+                         "vnf-parameter-value": "m1.medium"
+                    }, {
+                         "vnf-parameter-name": "install_script_version",
+                         "vnf-parameter-value": "1.4.0"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_0",
+                         "vnf-parameter-value": "192.168.10.100"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_1",
+                         "vnf-parameter-value": "192.168.20.100"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_2",
+                         "vnf-parameter-value": "10.0.110.1"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_3",
+                         "vnf-parameter-value": "10.100.100.1"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_0",
+                         "vnf-parameter-value": "192.168.10.200"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_1",
+                         "vnf-parameter-value": "10.0.110.2"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_2",
+                         "vnf-parameter-value": "10.100.100.2"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_1",
+                         "vnf-parameter-value": "10.0.110.3"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_0",
+                         "vnf-parameter-value": "192.168.20.250"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_2",
+                         "vnf-parameter-value": "10.100.100.3"
+                    }, {
+                         "vnf-parameter-name": "demo_artifacts_version",
+                         "vnf-parameter-value": "1.4.0"
+                    }, {
+                         "vnf-parameter-name": "pub_key",
+                         "vnf-parameter-value": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6KbTxfT368DNBzLyfTYJ0INI7mkRXc/xMpx349TXGBTQ06g2toN/p9OM188EGZd/qERRXcdnKY8lYULVIXZEoQbXTus2gTQWXy1zn5nhSkhste3L1uG+sjHySQHBj5NyOC32iNehRNu03bHi8XRBAOHZsXx6JpkltLXgWqQI91+h9i7I/4trpPyODtzz1DLIkbXv9woncwllKf4bmm+Bk6/OJKHuAlBdCLL5diZqODEZlKOyPPC9c07a835sskMgbscPrvBQigZFRNerjQlFXXCHjRwoBMvfS7kD7/R/K1fmSLtH0w4VEp5iwS9SIezgEeO2aDFPucmYG4MQDGzAz"
+                    }, {
+                         "vnf-parameter-name": "dcae_collector_ip",
+                         "vnf-parameter-value": "10.0.4.1"
+                    }, {
+                         "vnf-parameter-name": "sec_group",
+                         "vnf-parameter-value": "onap_sg_y3id"
+                    }
+               ],
+               "vnf-topology-identifier": {
+                    "service-type": "1c38ef10-0f14-4d78-876c-3cc10ff4e535",
+                    "vnf-type": "VfwsnkDistributetraffic..base_vfw..module-0",
+                    "generic-vnf-name": "vfw-vsnk-dt-1",
+                    "generic-vnf-type": "vFWSNK-DistributeTraffic 0",
+                    "vnf-name": "vfw-dt-module-1"
+               }
+          }
+     }
+}
diff --git a/tutorials/vFWDT/preloads/vfw-2-preload.json b/tutorials/vFWDT/preloads/vfw-2-preload.json
new file mode 100644 (file)
index 0000000..17b473e
--- /dev/null
@@ -0,0 +1,141 @@
+{
+     "input": {
+          "request-information": {
+               "notification-url": "openecomp.org",
+               "order-number": "1",
+               "order-version": "1",
+               "request-action": "PreloadVNFRequest",
+               "request-id": "robot12"
+          },
+          "sdnc-request-header": {
+               "svc-action": "reserve",
+               "svc-notification-url": "http:\/\/openecomp.org:8080\/adapters\/rest\/SDNCNotify",
+               "svc-request-id": "robot12"
+          },
+          "vnf-topology-information": {
+               "vnf-assignments": {
+                    "availability-zones": [],
+                    "vnf-networks": [],
+                    "vnf-vms": []
+               },
+               "vnf-parameters":
+               [{
+                         "vnf-parameter-name": "unprotected_private_net_id",
+                         "vnf-parameter-value": "unprotected_net_dt"
+                    }, {
+                         "vnf-parameter-name": "unprotected_private_subnet_id",
+                         "vnf-parameter-value": "unprotected_subnet_dt"
+                    }, {
+                         "vnf-parameter-name": "unprotected_private_net_cidr",
+                         "vnf-parameter-value": "192.168.10.0/24"
+                    }, {
+                         "vnf-parameter-name": "protected_private_net_id",
+                         "vnf-parameter-value": "protected_net_dt"
+                    }, {
+                         "vnf-parameter-name": "protected_private_net_cidr",
+                         "vnf-parameter-value": "192.168.20.0/24"
+                    }, {
+                         "vnf-parameter-name": "protected_private_subnet_id",
+                         "vnf-parameter-value": "protected_subnet_dt"
+                    }, {
+                         "vnf-parameter-name": "key_name",
+                         "vnf-parameter-value": "vfw_key"
+                    }, {
+                         "vnf-parameter-name": "cloud_env",
+                         "vnf-parameter-value": "openstack"
+                    }, {
+                         "vnf-parameter-name": "vsn_name_0",
+                         "vnf-parameter-value": "vfw-vsn-2-dt"
+                    }, {
+                         "vnf-parameter-name": "onap_private_net_id",
+                         "vnf-parameter-value": "oam_onap_y3id"
+                    }, {
+                         "vnf-parameter-name": "onap_private_subnet_id",
+                         "vnf-parameter-value": "oam_onap_y3id"
+                    }, {
+                         "vnf-parameter-name": "onap_private_net_cidr",
+                         "vnf-parameter-value": "10.0.0.0/16"
+                    }, {
+                         "vnf-parameter-name": "ext_private_net_id",
+                         "vnf-parameter-value": "onap_oam_ext"
+                    }, {
+                         "vnf-parameter-name": "ext_private_subnet_id",
+                         "vnf-parameter-value": "onap_oam_ext_sub"
+                    }, {
+                         "vnf-parameter-name": "ext_private_net_cidr",
+                         "vnf-parameter-value": "10.100.0.0/16"
+                    }, {
+                         "vnf-parameter-name": "nexus_artifact_repo",
+                         "vnf-parameter-value": "https://nexus.onap.org"
+                    }, {
+                         "vnf-parameter-name": "vfw_name_0",
+                         "vnf-parameter-value": "vfw-vfw-2-dt"
+                    }, {
+                         "vnf-parameter-name": "dcae_collector_port",
+                         "vnf-parameter-value": "8080"
+                    }, {
+                         "vnf-parameter-name": "public_net_id",
+                         "vnf-parameter-value": "external"
+                    }, {
+                         "vnf-parameter-name": "image_name",
+                         "vnf-parameter-value": "ubuntu-14-04-cloud-amd64"
+                    }, {
+                         "vnf-parameter-name": "flavor_name",
+                         "vnf-parameter-value": "m1.medium"
+                    }, {
+                         "vnf-parameter-name": "install_script_version",
+                         "vnf-parameter-value": "1.4.0"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_0",
+                         "vnf-parameter-value": "192.168.10.110"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_1",
+                         "vnf-parameter-value": "192.168.20.110"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_2",
+                         "vnf-parameter-value": "10.0.110.4"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_3",
+                         "vnf-parameter-value": "10.100.100.4"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_0",
+                         "vnf-parameter-value": "192.168.10.200"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_1",
+                         "vnf-parameter-value": "10.0.110.2"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_2",
+                         "vnf-parameter-value": "10.100.100.2"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_1",
+                         "vnf-parameter-value": "10.0.110.5"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_0",
+                         "vnf-parameter-value": "192.168.20.240"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_2",
+                         "vnf-parameter-value": "10.100.100.5"
+                    }, {
+                         "vnf-parameter-name": "demo_artifacts_version",
+                         "vnf-parameter-value": "1.4.0"
+                    }, {
+                         "vnf-parameter-name": "pub_key",
+                         "vnf-parameter-value": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6KbTxfT368DNBzLyfTYJ0INI7mkRXc/xMpx349TXGBTQ06g2toN/p9OM188EGZd/qERRXcdnKY8lYULVIXZEoQbXTus2gTQWXy1zn5nhSkhste3L1uG+sjHySQHBj5NyOC32iNehRNu03bHi8XRBAOHZsXx6JpkltLXgWqQI91+h9i7I/4trpPyODtzz1DLIkbXv9woncwllKf4bmm+Bk6/OJKHuAlBdCLL5diZqODEZlKOyPPC9c07a835sskMgbscPrvBQigZFRNerjQlFXXCHjRwoBMvfS7kD7/R/K1fmSLtH0w4VEp5iwS9SIezgEeO2aDFPucmYG4MQDGzAz"
+                    }, {
+                         "vnf-parameter-name": "dcae_collector_ip",
+                         "vnf-parameter-value": "10.0.4.1"
+                    }, {
+                         "vnf-parameter-name": "sec_group",
+                         "vnf-parameter-value": "onap_sg_y3id"
+                    }
+               ],
+               "vnf-topology-identifier": {
+                    "service-type": "1c38ef10-0f14-4d78-876c-3cc10ff4e535",
+                    "vnf-type": "VfwsnkDistributetraffic..base_vfw..module-0",
+                    "generic-vnf-name": "vfw-vsnk-dt-2",
+                    "generic-vnf-type": "vFWSNK-DistributeTraffic 1",
+                    "vnf-name": "vfw-dt-module-2"
+               }
+          }
+     }
+}
diff --git a/tutorials/vFWDT/preloads/vpkg-preload.json b/tutorials/vFWDT/preloads/vpkg-preload.json
new file mode 100644 (file)
index 0000000..8a303b2
--- /dev/null
@@ -0,0 +1,141 @@
+{
+     "input": {
+          "request-information": {
+               "notification-url": "openecomp.org",
+               "order-number": "1",
+               "order-version": "1",
+               "request-action": "PreloadVNFRequest",
+               "request-id": "robot12"
+          },
+          "sdnc-request-header": {
+               "svc-action": "reserve",
+               "svc-notification-url": "http:\/\/openecomp.org:8080\/adapters\/rest\/SDNCNotify",
+               "svc-request-id": "robot12"
+          },
+          "vnf-topology-information": {
+               "vnf-assignments": {
+                    "availability-zones": [],
+                    "vnf-networks": [],
+                    "vnf-vms": []
+               },
+               "vnf-parameters":
+               [{
+                         "vnf-parameter-name": "unprotected_private_net_id",
+                         "vnf-parameter-value": "unprotected_net_dt"
+                    }, {
+                         "vnf-parameter-name": "unprotected_private_subnet_id",
+                         "vnf-parameter-value": "unprotected_subnet_dt"
+                    }, {
+                         "vnf-parameter-name": "unprotected_private_net_cidr",
+                         "vnf-parameter-value": "192.168.10.0/24"
+                    }, {
+                         "vnf-parameter-name": "protected_private_net_id",
+                         "vnf-parameter-value": "protected_net_dt"
+                    }, {
+                         "vnf-parameter-name": "protected_private_net_cidr",
+                         "vnf-parameter-value": "192.168.20.0/24"
+                    }, {
+                         "vnf-parameter-name": "protected_private_subnet_id",
+                         "vnf-parameter-value": "protected_subnet_dt"
+                    }, {
+                         "vnf-parameter-name": "key_name",
+                         "vnf-parameter-value": "vfw_key"
+                    }, {
+                         "vnf-parameter-name": "cloud_env",
+                         "vnf-parameter-value": "openstack"
+                    }, {
+                         "vnf-parameter-name": "vsn_name_0",
+                         "vnf-parameter-value": "vfw-vsn-0-dt"
+                    }, {
+                         "vnf-parameter-name": "onap_private_net_id",
+                         "vnf-parameter-value": "oam_onap_y3id"
+                    }, {
+                         "vnf-parameter-name": "onap_private_subnet_id",
+                         "vnf-parameter-value": "oam_onap_y3id"
+                    }, {
+                         "vnf-parameter-name": "onap_private_net_cidr",
+                         "vnf-parameter-value": "10.0.0.0/16"
+                    }, {
+                         "vnf-parameter-name": "ext_private_net_id",
+                         "vnf-parameter-value": "onap_oam_ext"
+                    }, {
+                         "vnf-parameter-name": "ext_private_subnet_id",
+                         "vnf-parameter-value": "onap_oam_ext_sub"
+                    }, {
+                         "vnf-parameter-name": "ext_private_net_cidr",
+                         "vnf-parameter-value": "10.100.0.0/16"
+                    }, {
+                         "vnf-parameter-name": "nexus_artifact_repo",
+                         "vnf-parameter-value": "https://nexus.onap.org"
+                    }, {
+                         "vnf-parameter-name": "vfw_name_0",
+                         "vnf-parameter-value": "vfw-vfw-0-dt"
+                    }, {
+                         "vnf-parameter-name": "dcae_collector_port",
+                         "vnf-parameter-value": "8080"
+                    }, {
+                         "vnf-parameter-name": "public_net_id",
+                         "vnf-parameter-value": "external"
+                    }, {
+                         "vnf-parameter-name": "image_name",
+                         "vnf-parameter-value": "ubuntu-14-04-cloud-amd64"
+                    }, {
+                         "vnf-parameter-name": "flavor_name",
+                         "vnf-parameter-value": "m1.medium"
+                    }, {
+                         "vnf-parameter-name": "install_script_version",
+                         "vnf-parameter-value": "1.4.0"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_0",
+                         "vnf-parameter-value": "192.168.10.100"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_1",
+                         "vnf-parameter-value": "192.168.20.100"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_2",
+                         "vnf-parameter-value": "10.0.110.1"
+                    }, {
+                         "vnf-parameter-name": "vfw_private_ip_3",
+                         "vnf-parameter-value": "10.100.100.1"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_0",
+                         "vnf-parameter-value": "192.168.10.200"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_1",
+                         "vnf-parameter-value": "10.0.110.2"
+                    }, {
+                         "vnf-parameter-name": "vpg_private_ip_2",
+                         "vnf-parameter-value": "10.100.100.2"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_1",
+                         "vnf-parameter-value": "10.0.110.3"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_0",
+                         "vnf-parameter-value": "192.168.20.250"
+                    }, {
+                         "vnf-parameter-name": "vsn_private_ip_2",
+                         "vnf-parameter-value": "10.100.100.3"
+                    }, {
+                         "vnf-parameter-name": "demo_artifacts_version",
+                         "vnf-parameter-value": "1.4.0"
+                    }, {
+                         "vnf-parameter-name": "pub_key",
+                         "vnf-parameter-value": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6KbTxfT368DNBzLyfTYJ0INI7mkRXc/xMpx349TXGBTQ06g2toN/p9OM188EGZd/qERRXcdnKY8lYULVIXZEoQbXTus2gTQWXy1zn5nhSkhste3L1uG+sjHySQHBj5NyOC32iNehRNu03bHi8XRBAOHZsXx6JpkltLXgWqQI91+h9i7I/4trpPyODtzz1DLIkbXv9woncwllKf4bmm+Bk6/OJKHuAlBdCLL5diZqODEZlKOyPPC9c07a835sskMgbscPrvBQigZFRNerjQlFXXCHjRwoBMvfS7kD7/R/K1fmSLtH0w4VEp5iwS9SIezgEeO2aDFPucmYG4MQDGzAz"
+                    }, {
+                         "vnf-parameter-name": "dcae_collector_ip",
+                         "vnf-parameter-value": "10.0.4.1"
+                    }, {
+                         "vnf-parameter-name": "sec_group",
+                         "vnf-parameter-value": "onap_sg_y3id"
+                    }
+               ],
+               "vnf-topology-identifier": {
+                    "service-type": "1c38ef10-0f14-4d78-876c-3cc10ff4e535",
+                    "vnf-type": "VpkgDistributetraffic..base_vpkg..module-0",
+                    "generic-vnf-name": "vpkg-dt-1",
+                    "generic-vnf-type": "vPKG-DistributeTraffic 0",
+                    "vnf-name": "vpkg-dt-module-1"
+               }
+          }
+     }
+}
diff --git a/tutorials/vFWDT/workflow/README.md b/tutorials/vFWDT/workflow/README.md
new file mode 100644 (file)
index 0000000..defab10
--- /dev/null
@@ -0,0 +1,20 @@
+This python script is used to execute Traffic Distribution workflow on vFWDT service instance.
+It uses AAI, OOF and APPC API to perform steps necessary to distribute traffic from one to the other 
+instance of vFW. Full description of the the use case can be found in here
+
+[ONAP vFW Traffic Distribution Use Case](https://docs.onap.org/en/latest/submodules/integration.git/docs/docs_vFWDT.html)
+
+Usage:
+
+`pip3 install -r requirements.txt --user`
+
+`python3 workflow.py 55f59a16-4c10-45e1-9873-6322a25d040a 10.12.5.63 True False False True`
+
+Input parameters:
+* vnf-id of vFW VNF instance that traffic should be migrated out from
+* IP of ONAP OOM Node (any)
+* if script should use and build OOF response cache
+* if instead of vFWDT service instance vFW or vFWCL one is used
+* if only configuration information will be collected
+* if APPC LCM action status should be verified and FAILURE should stop workflow
+
diff --git a/tutorials/vFWDT/workflow/requirements.txt b/tutorials/vFWDT/workflow/requirements.txt
new file mode 100644 (file)
index 0000000..2b2e820
--- /dev/null
@@ -0,0 +1,3 @@
+netifaces>=0.10.9
+simple-rest-client>=0.5.4
+basicauth>=0.4.1
\ No newline at end of file
diff --git a/tutorials/vFWDT/workflow/templates/appcDmaapLcm.json b/tutorials/vFWDT/workflow/templates/appcDmaapLcm.json
new file mode 100644 (file)
index 0000000..5be6627
--- /dev/null
@@ -0,0 +1,28 @@
+{
+    "body": {
+        "input": {
+            "action": "DistributeTraffic",
+            "payload": "{\"configuration-parameters\":{\"ConfigFileName\":\"/opt/onap/ccsdk/Playbooks/dt-vpkg-1-config.json\",\"playbook\":\"ansible_vfw_distributetraffic@0.00.yml\",\"node_list\":\"[vpkg-1]\"}}",
+            "common-header": {
+                "api-ver": "2.00",
+                "timestamp": "2018-10-22T11:11:25.244Z",
+                "flags": {
+                    "force": "TRUE",
+                    "mode": "NORMAL",
+                    "ttl": 36000
+                },
+                "request-id": 27081074,
+                "originator-id": "demo",
+                "sub-request-id": "1540197850899"
+            },
+            "action-identifiers": {
+                "vnf-id": "50ac9605-ce63-442d-a103-80e9cf4753ca"
+            }
+        }
+    },
+    "cambria.partition": "APPC",
+    "rpc-name": "distribute-traffic",
+    "correlation-id": "c09ac7d1-de62-0016-2000-e63701125557-201",
+    "version": "2.0",
+    "type": "request"
+}
\ No newline at end of file
diff --git a/tutorials/vFWDT/workflow/templates/appcRestconfLcm.json b/tutorials/vFWDT/workflow/templates/appcRestconfLcm.json
new file mode 100644 (file)
index 0000000..fa0eb79
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "input": {
+    "action": "DistributeTraffic",
+    "payload": "{\"configuration-parameters\":{\"file_parameter_content\":\"{\\\"fwIp\\\":\\\"192.168.10.100\\\",\\\"sinkIp\\\":\\\"192.168.20.250\\\"}\",\"node_list\":\"[vpkg-1]\"}}",
+    "common-header": {
+      "api-ver": "2.00",
+      "timestamp": "2019-05-20T08:18:07.244Z",
+      "flags": {
+        "force": "TRUE",
+        "mode": "NORMAL",
+        "ttl": 36000
+      },
+      "request-id": "8ac122fd-6261-4e72-ba5c-5384fcd0ab2b",
+      "originator-id": "vfw-dt-demo",
+      "sub-request-id": "cefe9354-809d-4dd2-ab6d-e1f9d2fa9ea3"
+    },
+    "action-identifiers": {
+      "vnf-id": "2d125b4d-e120-4815-a0c7-4c4bec6c89f9"
+    }
+  }
+}
\ No newline at end of file
diff --git a/tutorials/vFWDT/workflow/templates/hasRequest.json b/tutorials/vFWDT/workflow/templates/hasRequest.json
new file mode 100644 (file)
index 0000000..a58d4dd
--- /dev/null
@@ -0,0 +1,93 @@
+{
+    "name": "de4f04e3-0a65-470b-9d07-8ea6c2fb3e10",
+    "template": {
+        "constraints": {
+            "affinity_vFW_TD": {
+                "demands": ["vFW-SINK", "vPGN"],
+                "properties": {
+                    "category": "region",
+                    "qualifier": "same"
+                },
+                "type": "zone"
+            }
+        },
+        "parameters": {
+            "service_name": "vFW_TD",
+            "chosen_region": "RegionOne",
+            "chosen_customer_id": "DemoCust_4fb7d3cf-5ddc-4d8c-8acf-70cc9174d18f",
+            "service_id": "2ad369d4-9056-4dc9-8e6d-df24f45e8729",
+            "customer_long": 2.2,
+            "REQUIRED_MEM": "",
+            "customer_lat": 1.1,
+            "REQUIRED_DISK": ""
+        },
+        "locations": {
+            "customer_loc": {
+                "longitude": {
+                    "get_param": "customer_long"
+                },
+                "latitude": {
+                    "get_param": "customer_lat"
+                }
+            }
+        },
+        "demands": {
+            "vFW-SINK": [{
+                "attributes": {
+                    "global-customer-id": {
+                        "get_param": "chosen_customer_id"
+                    },
+                    "cloud-region-id": {
+                        "get_param": "chosen_region"
+                    },
+                    "model-version-id": "202d2fd8-a045-4c9a-b767-2a1639c10291",
+                    "orchestration-status": ["active"],
+                    "model-invariant-id": "6f3fd439-fd5f-4a2d-95bc-b6bf8787001a",
+                    "service_instance_id": {
+                        "get_param": "service_id"
+                    },
+                    "prov-status": "ACTIVE"
+                },
+                "inventory_provider": "aai",
+                "service_resource_id": "vFW-SINK-XX",
+                "inventory_type": "vfmodule",
+                "service_type": "vFW-SINK-XX",
+                "excluded_candidates": [{
+                    "inventory_type": "vfmodule",
+                    "candidate_id": "e765d576-8755-4145-8536-0bb6d9b1dc9a"
+                }],
+                "required_candidates": [{
+                    "inventory_type": "vfmodule",
+                    "candidate_id": "e765d576-8755-4145-8536-0bb6d9b1dc9a"
+                }]
+            }],
+            "vPGN": [{
+                "attributes": {
+                    "global-customer-id": {
+                        "get_param": "chosen_customer_id"
+                    },
+                    "cloud-region-id": {
+                        "get_param": "chosen_region"
+                    },
+                    "model-version-id": "6bfe954e-bb00-4111-be3c-33eed9d20a8c",
+                    "orchestration-status": ["active"],
+                    "model-invariant-id": "3f356335-7b36-41ee-8f74-72d0a2ec3ebf",
+                    "service_instance_id": {
+                        "get_param": "service_id"
+                    },
+                    "prov-status": "ACTIVE"
+                },
+                "inventory_provider": "aai",
+                "service_resource_id": "vPGN-XX",
+                "unique": "false",
+                "inventory_type": "vfmodule",
+                "service_type": "vPGN-XX"
+            }]
+        },
+        "homing_template_version": "2017-10-10"
+    },
+    "limit": 100,
+    "num_solution": "100",
+    "files": {},
+    "timeout": 1200
+}
diff --git a/tutorials/vFWDT/workflow/templates/osdfRequest.json b/tutorials/vFWDT/workflow/templates/osdfRequest.json
new file mode 100644 (file)
index 0000000..1bef055
--- /dev/null
@@ -0,0 +1,65 @@
+{
+  "requestInfo": {
+    "transactionId": "e576c75e-7536-4145-a1c0-d60b65bb1bb8",
+    "requestId": "de4f04e3-0a65-470b-9d07-8ea6c2fb3e10",
+    "callbackUrl": "http://0.0.0.0:9000/osdfCallback/",
+    "sourceId": "SO",
+    "requestType": "create",
+    "numSolutions": 100,
+    "optimizers": [
+      "placement"
+    ],
+    "timeout": 1200
+  },
+  "placementInfo": {
+    "requestParameters": {
+      "chosenRegion": "RegionOne",
+      "chosenCustomerId": "DemoCust_8b908ab3-b9e6-41a9-a4e2-31cc9c5114a2"
+    },
+    "subscriberInfo": {
+      "globalSubscriberId": "dbc2c763-6383-42d6-880a-b7d5c5bc84d9",
+      "subscriberName": "oof-so-chm"
+    },
+    "placementDemands": [
+      {
+        "resourceModuleName": "vFW-SINK",
+        "serviceResourceId": "vFW-SINK-XX",
+        "resourceModelInfo": {
+          "modelInvariantId": "fda3c1e8-7653-4acd-80ef-f5755c1d3859",
+          "modelVersionId": "a6906768-1cae-4e78-acd1-d753ac61f3e8"
+        },
+        "excludedCandidates": [
+          {
+            "identifierType": "vfmodule",
+            "identifiers": [
+            ]
+          }
+        ],
+        "requiredCandidates": [
+          {
+            "identifierType": "vfmodule",
+            "identifiers": [
+            ]
+          }
+        ]
+      },
+      {
+        "resourceModuleName": "vPGN",
+        "serviceResourceId": "vPGN-XX",
+        "unique": "false",
+        "resourceModelInfo": {
+          "modelInvariantId": "f2f88e29-d571-49ef-aea3-b8d13900c16f",
+          "modelVersionId": "3ccebc76-66e1-47c8-aee9-98f30d08db97"
+        }
+      }
+    ]
+  },
+  "serviceInfo": {
+    "serviceInstanceId": "209fb01e-60ca-4325-b074-c5ad4e0499f8",
+    "serviceName": "TD",
+    "modelInfo": {
+      "modelInvariantId": "TD-invariantId",
+      "modelVersionId": "TD-versionId"
+    }
+  }
+}
\ No newline at end of file
diff --git a/tutorials/vFWDT/workflow/workflow.py b/tutorials/vFWDT/workflow/workflow.py
new file mode 100644 (file)
index 0000000..f34448c
--- /dev/null
@@ -0,0 +1,584 @@
+'''
+/*-
+* ============LICENSE_START=======================================================
+* Copyright (C) 2019 Orange
+* ================================================================================
+* 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.
+*
+* ============LICENSE_END=========================================================
+*/
+'''
+
+import os
+import json
+import sys
+import uuid
+import time
+import copy
+import netifaces as ni
+import warnings
+import contextlib
+import requests
+from datetime import datetime
+from datetime import timedelta
+from simple_rest_client.api import API
+from simple_rest_client.resource import Resource
+from basicauth import encode
+from pprint import pprint
+from random import randint
+from urllib3.exceptions import InsecureRequestWarning
+
+
+old_merge_environment_settings = requests.Session.merge_environment_settings
+
+hostname_cache = []
+ansible_inventory = {}
+
+
+@contextlib.contextmanager
+def _no_ssl_verification():
+    opened_adapters = set()
+
+    def merge_environment_settings(self, url, proxies, stream, verify, cert):
+        # Verification happens only once per connection so we need to close
+        # all the opened adapters once we're done. Otherwise, the effects of
+        # verify=False persist beyond the end of this context manager.
+        opened_adapters.add(self.get_adapter(url))
+
+        settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
+        settings['verify'] = False
+
+        return settings
+
+    requests.Session.merge_environment_settings = merge_environment_settings
+
+    try:
+        with warnings.catch_warnings():
+            warnings.simplefilter('ignore', InsecureRequestWarning)
+            yield
+    finally:
+        requests.Session.merge_environment_settings = old_merge_environment_settings
+
+        for adapter in opened_adapters:
+            try:
+                adapter.close()
+            except:
+                pass
+
+
+def _get_aai_rel_link_data(data, related_to, search_key=None, match_dict=None):
+    # some strings that we will encounter frequently
+    rel_lst = "relationship-list"
+    rkey = "relationship-key"
+    rval = "relationship-value"
+    rdata = "relationship-data"
+    response = list()
+    if match_dict:
+        m_key = match_dict.get('key')
+        m_value = match_dict.get('value')
+    else:
+        m_key = None
+        m_value = None
+    rel_dict = data.get(rel_lst)
+    if rel_dict:  # check if data has relationship lists
+        for key, rel_list in rel_dict.items():
+            for rel in rel_list:
+                if rel.get("related-to") == related_to:
+                    dval = None
+                    matched = False
+                    link = rel.get("related-link")
+                    r_data = rel.get(rdata, [])
+                    if search_key:
+                        for rd in r_data:
+                            if rd.get(rkey) == search_key:
+                                dval = rd.get(rval)
+                                if not match_dict:  # return first match
+                                    response.append(
+                                        {"link": link, "d_value": dval}
+                                    )
+                                    break  # go to next relation
+                            if rd.get(rkey) == m_key \
+                                    and rd.get(rval) == m_value:
+                                matched = True
+                        if match_dict and matched:  # if matching required
+                            response.append(
+                                {"link": link, "d_value": dval}
+                            )
+                            # matched, return search value corresponding
+                            # to the matched r_data group
+                    else:  # no search key; just return the link
+                        response.append(
+                            {"link": link, "d_value": dval}
+                        )
+    if len(response) == 0:
+        response.append(
+            {"link": None, "d_value": None}
+        )
+    return response
+
+
+class AAIApiResource(Resource):
+    actions = {
+        'generic_vnf': {'method': 'GET', 'url': 'network/generic-vnfs/generic-vnf/{}'},
+        'link': {'method': 'GET', 'url': '{}'},
+        'service_instance': {'method': 'GET',
+                             'url': 'business/customers/customer/{}/service-subscriptions/service-subscription/{}/service-instances/service-instance/{}'}
+    }
+
+
+class HASApiResource(Resource):
+    actions = {
+        'plans': {'method': 'POST', 'url': 'plans/'},
+        'plan': {'method': 'GET', 'url': 'plans/{}'}
+    }
+
+
+class APPCLcmApiResource(Resource):
+    actions = {
+        'distribute_traffic': {'method': 'POST', 'url': 'appc-provider-lcm:distribute-traffic/'},
+        'distribute_traffic_check': {'method': 'POST', 'url': 'appc-provider-lcm:distribute-traffic-check/'},
+        'action_status': {'method': 'POST', 'url': 'appc-provider-lcm:action-status/'},
+    }
+
+
+def _init_python_aai_api(onap_ip):
+    api = API(
+        api_root_url="https://{}:30233/aai/v14/".format(onap_ip),
+        params={},
+        headers={
+            'Authorization': encode("AAI", "AAI"),
+            'X-FromAppId': 'SCRIPT',
+            'Accept': 'application/json',
+            'Content-Type': 'application/json',
+            'X-TransactionId': str(uuid.uuid4()),
+        },
+        timeout=30,
+        append_slash=False,
+        json_encode_body=True # encode body as json
+    )
+    api.add_resource(resource_name='aai', resource_class=AAIApiResource)
+    return api
+
+
+def _init_python_has_api(onap_ip):
+    api = API(
+        api_root_url="https://{}:30275/v1/".format(onap_ip),
+        params={},
+        headers={
+            'Authorization': encode("admin1", "plan.15"),
+            'X-FromAppId': 'SCRIPT',
+            'Accept': 'application/json',
+            'Content-Type': 'application/json',
+            'X-TransactionId': str(uuid.uuid4()),
+        },
+        timeout=30,
+        append_slash=False,
+        json_encode_body=True # encode body as json
+    )
+    api.add_resource(resource_name='has', resource_class=HASApiResource)
+    return api
+
+
+def _init_python_appc_lcm_api(onap_ip):
+    api = API(
+        api_root_url="http://{}:30230/restconf/operations/".format(onap_ip),
+        params={},
+        headers={
+            'Authorization': encode("admin", "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"),
+            'X-FromAppId': 'SCRIPT',
+            'Accept': 'application/json',
+            'Content-Type': 'application/json',
+        },
+        timeout=300,
+        append_slash=False,
+        json_encode_body=True # encode body as json
+    )
+    api.add_resource(resource_name='lcm', resource_class=APPCLcmApiResource)
+    return api
+
+
+def load_aai_data(vfw_vnf_id, onap_ip):
+    api = _init_python_aai_api(onap_ip)
+    aai_data = {}
+    aai_data['service-info'] = {'global-customer-id': '', 'service-instance-id': '', 'service-type': ''}
+    aai_data['vfw-model-info'] = {'model-invariant-id': '', 'model-version-id': '', 'vnf-name': '', 'vnf-type': ''}
+    aai_data['vpgn-model-info'] = {'model-invariant-id': '', 'model-version-id': '', 'vnf-name': '', 'vnf-type': ''}
+    with _no_ssl_verification():
+        response = api.aai.generic_vnf(vfw_vnf_id, body=None, params={'depth': 2}, headers={})
+        aai_data['vfw-model-info']['model-invariant-id'] = response.body.get('model-invariant-id')
+        aai_data['vfw-model-info']['model-version-id'] = response.body.get('model-version-id')
+        aai_data['vfw-model-info']['vnf-name'] = response.body.get('vnf-name')
+        aai_data['vfw-model-info']['vnf-type'] = response.body.get('vnf-type')
+        aai_data['vf-module-id'] = response.body['vf-modules']['vf-module'][0]['vf-module-id']
+
+        related_to = "service-instance"
+        search_key = "customer.global-customer-id"
+        rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
+        aai_data['service-info']['global-customer-id'] = rl_data_list[0]['d_value']
+
+        search_key = "service-subscription.service-type"
+        rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
+        aai_data['service-info']['service-type'] = rl_data_list[0]['d_value']
+
+        search_key = "service-instance.service-instance-id"
+        rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
+        aai_data['service-info']['service-instance-id'] = rl_data_list[0]['d_value']
+
+        service_link = rl_data_list[0]['link']
+        response = api.aai.link(service_link, body=None, params={}, headers={})
+
+        related_to = "generic-vnf"
+        search_key = "generic-vnf.vnf-id"
+        rl_data_list = _get_aai_rel_link_data(data=response.body, related_to=related_to, search_key=search_key)
+        for i in range(0, len(rl_data_list)):
+            vnf_id = rl_data_list[i]['d_value']
+
+            if vnf_id != vfw_vnf_id:
+                vnf_link = rl_data_list[i]['link']
+                response = api.aai.link(vnf_link, body=None, params={}, headers={})
+                if aai_data['vfw-model-info']['model-invariant-id'] != response.body.get('model-invariant-id'):
+                    aai_data['vpgn-model-info']['model-invariant-id'] = response.body.get('model-invariant-id')
+                    aai_data['vpgn-model-info']['model-version-id'] = response.body.get('model-version-id')
+                    aai_data['vpgn-model-info']['vnf-name'] = response.body.get('vnf-name')
+                    aai_data['vpgn-model-info']['vnf-type'] = response.body.get('vnf-type')
+                    break
+    return aai_data
+
+
+def _has_request(onap_ip, aai_data, exclude, use_oof_cache):
+    dirname = os.path.join('templates/oof-cache/', aai_data['vf-module-id'])
+    if exclude:
+        file = os.path.join(dirname, 'sample-has-excluded.json')
+    else:
+        file = os.path.join(dirname, 'sample-has-required.json')
+    if use_oof_cache and os.path.exists(file):
+        migrate_from = json.loads(open(file).read())
+        return migrate_from
+
+    print('Making HAS request for excluded {}'.format(str(exclude)))
+    api = _init_python_has_api(onap_ip)
+    request_id = str(uuid.uuid4())
+    template = json.loads(open('templates/hasRequest.json').read())
+    result = {}
+    template['name'] = request_id
+    node = template['template']['parameters']
+    node['chosen_customer_id'] = aai_data['service-info']['global-customer-id']
+    node['service_id'] = aai_data['service-info']['service-instance-id']
+    node = template['template']['demands']['vFW-SINK'][0]
+    node['attributes']['model-invariant-id'] = aai_data['vfw-model-info']['model-invariant-id']
+    node['attributes']['model-version-id'] = aai_data['vfw-model-info']['model-version-id']
+    if exclude:
+        node['excluded_candidates'][0]['candidate_id'] = aai_data['vf-module-id']
+        del node['required_candidates']
+    else:
+        node['required_candidates'][0]['candidate_id'] = aai_data['vf-module-id']
+        del node['excluded_candidates']
+    node = template['template']['demands']['vPGN'][0]
+    node['attributes']['model-invariant-id'] = aai_data['vpgn-model-info']['model-invariant-id']
+    node['attributes']['model-version-id'] = aai_data['vpgn-model-info']['model-version-id']
+
+    with _no_ssl_verification():
+        response = api.has.plans(body=template, params={}, headers={})
+        if response.body.get('error_message') is not None:
+            raise Exception(response.body['error_message']['explanation'])
+        else:
+            plan_id = response.body['id']
+            response = api.has.plan(plan_id, body=None, params={}, headers={})
+            status = response.body['plans'][0]['status']
+            while status != 'done' and status != 'error':
+                print(status)
+                response = api.has.plan(plan_id, body=None, params={}, headers={})
+                status = response.body['plans'][0]['status']
+            if status == 'done':
+                result = response.body['plans'][0]['recommendations'][0]
+            else:
+                raise Exception(response.body['plans'][0]['message'])
+
+    if not os.path.exists(dirname):
+        os.makedirs(dirname)
+    f = open(file, 'w+')
+    f.write(json.dumps(result, indent=4))
+    f.close()
+    return result
+
+
+def _extract_has_appc_identifiers(has_result, demand):
+    if demand == 'vPGN':
+        v_server = has_result[demand]['attributes']['vservers'][0]
+    else:
+        if len(has_result[demand]['attributes']['vservers'][0]['l-interfaces']) == 4:
+            v_server = has_result[demand]['attributes']['vservers'][0]
+        else:
+            v_server = has_result[demand]['attributes']['vservers'][1]
+    for itf in v_server['l-interfaces']:
+        if itf['ipv4-addresses'][0].startswith("10.0."):
+            ip = itf['ipv4-addresses'][0]
+            break
+
+    if v_server['vserver-name'] in hostname_cache and demand != 'vPGN':
+        v_server['vserver-name'] = v_server['vserver-name'].replace("01", "02")
+    hostname_cache.append(v_server['vserver-name'])
+
+    config = {
+        'vnf-id': has_result[demand]['attributes']['nf-id'],
+        'vf-module-id': has_result[demand]['attributes']['vf-module-id'],
+        'ip': ip,
+        'vserver-id': v_server['vserver-id'],
+        'vserver-name': v_server['vserver-name'],
+        'vnfc-type': demand.lower(),
+        'physical-location-id': has_result[demand]['attributes']['physical-location-id']
+    }
+    ansible_inventory_entry = "{} ansible_ssh_host={} ansible_ssh_user=ubuntu".format(config['vserver-name'], config['ip'])
+    if demand.lower() not in ansible_inventory:
+        ansible_inventory[demand.lower()] = {}
+    ansible_inventory[demand.lower()][config['vserver-name']] = ansible_inventory_entry
+    return config
+
+
+def _extract_has_appc_dt_config(has_result, demand):
+    if demand == 'vPGN':
+        return {}
+    else:
+        config = {
+            "nf-type": has_result[demand]['attributes']['nf-type'],
+            "nf-name": has_result[demand]['attributes']['nf-name'],
+            "vf-module-name": has_result[demand]['attributes']['vf-module-name'],
+            "vnf-type": has_result[demand]['attributes']['vnf-type'],
+            "service_instance_id": "319e60ef-08b1-47aa-ae92-51b97f05e1bc",
+            "cloudClli": has_result[demand]['attributes']['physical-location-id'],
+            "nf-id": has_result[demand]['attributes']['nf-id'],
+            "vf-module-id": has_result[demand]['attributes']['vf-module-id'],
+            "aic_version": has_result[demand]['attributes']['aic_version'],
+            "ipv4-oam-address": has_result[demand]['attributes']['ipv4-oam-address'],
+            "vnfHostName": has_result[demand]['candidate']['host_id'],
+            "ipv6-oam-address": has_result[demand]['attributes']['ipv6-oam-address'],
+            "cloudOwner": has_result[demand]['candidate']['cloud_owner'],
+            "isRehome": has_result[demand]['candidate']['is_rehome'],
+            "locationId": has_result[demand]['candidate']['location_id'],
+            "locationType": has_result[demand]['candidate']['location_type'],
+            'vservers': has_result[demand]['attributes']['vservers']
+        }
+        return config
+
+
+def _build_config_from_has(has_result):
+    v_pgn_result = _extract_has_appc_identifiers(has_result, 'vPGN')
+    v_fw_result = _extract_has_appc_identifiers(has_result, 'vFW-SINK')
+    dt_config = _extract_has_appc_dt_config(has_result, 'vFW-SINK')
+
+    config = {
+        'vPGN': v_pgn_result,
+        'vFW-SINK': v_fw_result
+    }
+    #print(json.dumps(config, indent=4))
+    config['dt-config'] = {
+        'destinations': [dt_config]
+    }
+    return config
+
+
+def _build_appc_lcm_dt_payload(is_vpkg, oof_config, book_name, traffic_presence):
+    is_check = traffic_presence is not None
+    oof_config = copy.deepcopy(oof_config)
+    #if is_vpkg:
+    #    node_list = "[ {} ]".format(oof_config['vPGN']['vserver-id'])
+    #else:
+    #    node_list = "[ {} ]".format(oof_config['vFW-SINK']['vserver-id'])
+
+    if is_vpkg:
+        config = oof_config['vPGN']
+    else:
+        config = oof_config['vFW-SINK']
+    #node = {
+    #    'site': config['physical-location-id'],
+    #    'vnfc_type': config['vnfc-type'],
+    #    'vm_info': [{
+    #        'ne_id': config['vserver-name'],
+    #        'fixed_ip_address': config['ip']
+    #   }]
+    #}
+    #node_list = list()
+    #node_list.append(node)
+
+    if is_check:
+        oof_config['dt-config']['trafficpresence'] = traffic_presence
+
+    file_content = oof_config['dt-config']
+
+    config = {
+        "configuration-parameters": {
+            #"node_list": node_list,
+            "ne_id": config['vserver-name'],
+            "fixed_ip_address": config['ip'],
+            "file_parameter_content":  json.dumps(file_content)
+        }
+    }
+    if book_name != '':
+        config["configuration-parameters"]["book_name"] = book_name
+    payload = json.dumps(config)
+    return payload
+
+
+def _build_appc_lcm_status_body(req):
+    payload = {
+        'request-id': req['input']['common-header']['request-id'],
+        'sub-request-id': req['input']['common-header']['sub-request-id'],
+        'originator-id': req['input']['common-header']['originator-id']
+    }
+    payload = json.dumps(payload)
+    template = json.loads(open('templates/appcRestconfLcm.json').read())
+    template['input']['action'] = 'ActionStatus'
+    template['input']['payload'] = payload
+    template['input']['common-header']['request-id'] = req['input']['common-header']['request-id']
+    template['input']['common-header']['sub-request-id'] = str(uuid.uuid4())
+    template['input']['action-identifiers']['vnf-id'] = req['input']['action-identifiers']['vnf-id']
+    return template
+
+
+def _build_appc_lcm_request_body(is_vpkg, config, req_id, action, traffic_presence=None):
+    if is_vpkg:
+        demand = 'vPGN'
+    else:
+        demand = 'vFW-SINK'
+
+    book_name = "{}/latest/ansible/{}/site.yml".format(demand.lower(), action.lower())
+    payload = _build_appc_lcm_dt_payload(is_vpkg, config, book_name, traffic_presence)
+    template = json.loads(open('templates/appcRestconfLcm.json').read())
+    template['input']['action'] = action
+    template['input']['payload'] = payload
+    template['input']['common-header']['request-id'] = req_id
+    template['input']['common-header']['sub-request-id'] = str(uuid.uuid4())
+    template['input']['action-identifiers']['vnf-id'] = config[demand]['vnf-id']
+    return template
+
+
+def _set_appc_lcm_timestamp(body, timestamp=None):
+    if timestamp is None:
+        t = datetime.utcnow() + timedelta(seconds=-10)
+        timestamp = t.strftime('%Y-%m-%dT%H:%M:%S.244Z')
+    body['input']['common-header']['timestamp'] = timestamp
+
+
+def build_appc_lcms_requests_body(onap_ip, aai_data, use_oof_cache, if_close_loop_vfw):
+    migrate_from = _has_request(onap_ip, aai_data, False, use_oof_cache)
+
+    if if_close_loop_vfw:
+        migrate_to = migrate_from
+    else:
+        migrate_to = _has_request(onap_ip, aai_data, True, use_oof_cache)
+
+    migrate_from = _build_config_from_has(migrate_from)
+    migrate_to = _build_config_from_has(migrate_to)
+    req_id = str(uuid.uuid4())
+    payload_dt_check_vpkg = _build_appc_lcm_request_body(True, migrate_from, req_id, 'DistributeTrafficCheck', True)
+    payload_dt_vpkg_to = _build_appc_lcm_request_body(True, migrate_to, req_id, 'DistributeTraffic')
+    payload_dt_check_vfw_from = _build_appc_lcm_request_body(False, migrate_from, req_id, 'DistributeTrafficCheck',
+                                                             False)
+    payload_dt_check_vfw_to = _build_appc_lcm_request_body(False, migrate_to, req_id, 'DistributeTrafficCheck', True)
+
+    result = list()
+    result.append(payload_dt_check_vpkg)
+    result.append(payload_dt_vpkg_to)
+    result.append(payload_dt_check_vfw_from)
+    result.append(payload_dt_check_vfw_to)
+    return result
+
+
+def appc_lcm_request(onap_ip, req):
+    api = _init_python_appc_lcm_api(onap_ip)
+    #print(json.dumps(req, indent=4))
+    if req['input']['action'] == "DistributeTraffic":
+        result = api.lcm.distribute_traffic(body=req, params={}, headers={})
+    elif req['input']['action'] == "DistributeTrafficCheck":
+        result = api.lcm.distribute_traffic_check(body=req, params={}, headers={})
+    else:
+        raise Exception("{} action not supported".format(req['input']['action']))
+
+    if result.body['output']['status']['code'] == 400:
+        print("Request Completed")
+    elif result.body['output']['status']['code'] == 100:
+        print("Request Accepted. Receiving result status...")
+#    elif result.body['output']['status']['code'] == 311:
+#        timestamp = result.body['output']['common-header']['timestamp']
+#        _set_appc_lcm_timestamp(req, timestamp)
+#        appc_lcm_request(onap_ip, req)
+#        return
+    else:
+        raise Exception("{} - {}".format(result.body['output']['status']['code'],
+                                         result.body['output']['status']['message']))
+    #print(result)
+    return result.body['output']['status']['code']
+
+
+def appc_lcm_status_request(onap_ip, req):
+    api = _init_python_appc_lcm_api(onap_ip)
+    status_body = _build_appc_lcm_status_body(req)
+    _set_appc_lcm_timestamp(status_body)
+
+    result = api.lcm.action_status(body=status_body, params={}, headers={})
+
+    if result.body['output']['status']['code'] == 400:
+        status = json.loads(result.body['output']['payload'])
+        return status
+    else:
+        raise Exception("{} - {}".format(result.body['output']['status']['code'],
+                                         result.body['output']['status']['message']))
+
+
+def confirm_appc_lcm_action(onap_ip, req, check_appc_result):
+    print("Checking LCM {} Status".format(req['input']['action']))
+
+    while True:
+        time.sleep(2)
+        status = appc_lcm_status_request(onap_ip, req)
+        print(status['status'])
+        if status['status'] == 'SUCCESSFUL':
+            return
+        elif status['status'] == 'IN_PROGRESS':
+            continue
+        elif check_appc_result:
+            raise Exception("LCM {} {} - {}".format(req['input']['action'], status['status'], status['status-reason']))
+        else:
+            return
+
+
+def execute_workflow(vfw_vnf_id, onap_ip, use_oof_cache, if_close_loop_vfw, info_only, check_result):
+    print("\nExecuting workflow for VNF ID '{}' on ONAP with IP {}".format(vfw_vnf_id, onap_ip))
+    print("\nOOF Cache {}, is CL vFW {}, only info {}, check LCM result {}".format(use_oof_cache, if_close_loop_vfw,
+                                                                                   info_only, check_result))
+    aai_data = load_aai_data(vfw_vnf_id, onap_ip)
+    print("\nvFWDT Service Information:")
+    print(json.dumps(aai_data, indent=4))
+    lcm_requests = build_appc_lcms_requests_body(onap_ip, aai_data, use_oof_cache, if_close_loop_vfw)
+    print("\nAnsible Inventory:")
+    for key in ansible_inventory:
+        print("[{}]".format(key))
+        for host in ansible_inventory[key]:
+            print(ansible_inventory[key][host])
+
+    if info_only:
+        return
+    print("\nDistribute Traffic Workflow Execution:")
+    for i in range(len(lcm_requests)):
+        req = lcm_requests[i]
+        print("APPC REQ {} - {}".format(i, req['input']['action']))
+        _set_appc_lcm_timestamp(req)
+        result = appc_lcm_request(onap_ip, req)
+        if result == 100:
+            confirm_appc_lcm_action(onap_ip, req, check_result)
+            #time.sleep(30)
+
+
+#vnf_id, K8s node IP, use OOF cache, if close loop vfw, if info_only, if check APPC result
+execute_workflow(sys.argv[1], sys.argv[2], sys.argv[3].lower() == 'true', sys.argv[4].lower() == 'true',
+                 sys.argv[5].lower() == 'true', sys.argv[6].lower() == 'true')