Functest scripts, simulators, and payloads 39/39939/2
authorSastry Isukapalli <sastry@research.att.com>
Thu, 29 Mar 2018 02:21:30 +0000 (22:21 -0400)
committerSastry Isukapalli <sastry@research.att.com>
Thu, 29 Mar 2018 02:57:12 +0000 (22:57 -0400)
osdf/adapters/policy/utils.py:
   Removed duplicated code (group_policies and group_policies_gen are very similar,
   and group_policies seems to be not used
osdf/optimizers/placementopt/conductor/api_builder.py:
   changed param name from "grouped_policies" to "flat_policies"
tox.ini
   added starup and shutdown of simulators (flask app with mock payloads) in tox tests
rest all files/changes in "test/" folder
quite a few payload files
Patch set 2: removed a "print()" statement from simulator code

Issue-ID: OPTFRA-22
Change-Id: I0006c577fc459c7c884b55e8316c689afd151780
Signed-off-by: Sastry Isukapalli <sastry@research.att.com>
39 files changed:
osdf/adapters/policy/utils.py
osdf/optimizers/placementopt/conductor/api_builder.py
osdf/optimizers/placementopt/conductor/conductor.py
test/conductor/test_conductor_calls.py [new file with mode: 0644]
test/functest/scripts/sanity-check-simulators.sh [new file with mode: 0644]
test/functest/scripts/start-simulators.sh [new file with mode: 0755]
test/functest/scripts/stop-simulators.sh [new file with mode: 0755]
test/functest/simulators/has-api/response-payloads/flow1-success-simple/main.json [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/flow1-success-simple/status-done.json [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/flow1-success-simple/status-solving.json [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/flow2-error-right-away/main.json [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/orig/README.md [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/orig/status-done.json [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/orig/status-error.json [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/orig/status-solving.json [new file with mode: 0644]
test/functest/simulators/has-api/response-payloads/orig/status-template.json [new file with mode: 0644]
test/functest/simulators/oof_dependencies_simulators.py [new file with mode: 0755]
test/functest/simulators/policy/response-payloads/README.md [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/README.md [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/subscriber_policy.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json [new file with mode: 0644]
test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json [new file with mode: 0644]
test/functest/simulators/simulated-config/common_config.yaml [new file with mode: 0644]
test/functest/simulators/simulated-config/has_config.yaml [new file with mode: 0644]
test/functest/simulators/simulated-config/osdf_config.yaml [new file with mode: 0755]
test/functest/simulators/simulated-config/simulated-config [new symlink]
test/policy-local-files/has_policies_r2/meta-valid-policies.txt [deleted file]
test/test_PolicyCalls.py
tox.ini

index f165079..2f873af 100644 (file)
@@ -23,37 +23,6 @@ import itertools
 from osdf.utils.programming_utils import dot_notation, list_flatten
 
 
-def group_policies(flat_policies):
-    """Filter policies using the following steps:
-    1. Apply prioritization among the policies that are sharing the same policy type and resource type
-    2. Remove redundant policies that may applicable across different types of resource
-    3. Filter policies based on type and return
-    :param flat_policies: list of flat policies
-    :return: Filtered policies
-    """
-    filtered_policies = defaultdict(list)
-    policy_name = []
-    policies = [x for x in flat_policies if x['content'].get('policyType')]  # drop ones without 'policy_type'
-    policy_types = set([x['content'].get('policyType') for x in policies])
-    aggregated_policies = dict((x, defaultdict(list)) for x in policy_types)
-
-    for policy in policies:
-        policy_type = policy['content'].get('policyType')
-        for resource in policy['content'].get('resources', []):
-            aggregated_policies[policy_type][resource].append(policy)
-
-    for policy_type in aggregated_policies:
-        for resource in aggregated_policies[policy_type]:
-            if aggregated_policies[policy_type][resource]:
-                aggregated_policies[policy_type][resource].sort(key=lambda x: x['priority'], reverse=True)
-                prioritized_policy = aggregated_policies[policy_type][resource][0]
-                if prioritized_policy['policyName'] not in policy_name:
-                    # TODO: Check logic here... should policy appear only once across all groups?
-                    filtered_policies[prioritized_policy['content']['policyType']].append(prioritized_policy)
-                    policy_name.append(prioritized_policy['policyName'])
-    return filtered_policies
-
-
 def group_policies_gen(flat_policies, config):
     """Filter policies using the following steps:
     1. Apply prioritization among the policies that are sharing the same policy type and resource type
index e359500..b2a5bf7 100644 (file)
@@ -25,7 +25,8 @@ from osdf.adapters.policy.utils import group_policies_gen
 from osdf.utils.programming_utils import list_flatten
 
 
-def conductor_api_builder(request_json, flat_policies: list, local_config, template="templates/conductor_interface.json"):
+def conductor_api_builder(request_json, flat_policies: list, local_config,
+                          template="osdf/templates/conductor_interface.json"):
     """Build an OSDF southbound API call for HAS-Conductor/Placement optimization
     :param request_json: parameter data received from a client
     :param flat_policies: policy data received from the policy platform (flat policies)
index 41b901c..663857b 100644 (file)
@@ -32,12 +32,12 @@ from osdf.utils.interfaces import RestClient
 from osdf.operation.exceptions import BusinessException
 
 
-def request(req_object, osdf_config, grouped_policies):
+def request(req_object, osdf_config, flat_policies):
     """
     Process a placement request from a Client (build Conductor API call, make the call, return result)
     :param req_object: Request parameters from the client
     :param osdf_config: Configuration specific to SNIRO application (core + deployment)
-    :param grouped_policies: policies related to placement (fetched based on request, and grouped by policy type)
+    :param flat_policies: policies related to placement (fetched based on request)
     :param prov_status: provStatus retrieved from Subscriber policy
     :return: response from Conductor (accounting for redirects from Conductor service
     """
@@ -53,7 +53,7 @@ def request(req_object, osdf_config, grouped_policies):
     ping_wait_time = config.get('conductorPingWaitTime', 60)
 
     rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug, headers=headers)
-    conductor_req_json_str = conductor_api_builder(req_object, grouped_policies, local_config)
+    conductor_req_json_str = conductor_api_builder(req_object, flat_policies, local_config)
     conductor_req_json = json.loads(conductor_req_json_str)
 
     debug_log.debug("Sending first Conductor request for request_id {}".format(req_id))
diff --git a/test/conductor/test_conductor_calls.py b/test/conductor/test_conductor_calls.py
new file mode 100644 (file)
index 0000000..1a96da7
--- /dev/null
@@ -0,0 +1,49 @@
+# -------------------------------------------------------------------------
+#   Copyright (c) 2018 AT&T Intellectual Property
+#
+#   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.
+#
+# -------------------------------------------------------------------------
+#
+import unittest
+
+from osdf.optimizers.placementopt.conductor import conductor
+import osdf.config.loader as config_loader
+from osdf.utils.interfaces import json_from_file
+from osdf.utils.programming_utils import DotDict
+from osdf.adapters.policy import interface as pol
+
+
+class TestConductorCalls(unittest.TestCase):
+
+    def setUp(self):
+        self.config_spec = {
+            "deployment": "test/functest/simulators/simulated-config/osdf_config.yaml",
+            "core": "test/functest/simulators/simulated-config/common_config.yaml"
+        }
+        self.osdf_config = DotDict(config_loader.all_configs(**self.config_spec))
+        self.lp = self.osdf_config.core.get('osdf_temp', {}).get('local_policies', {}
+                                                                 ).get('placement_policy_files_vcpe')
+
+    def tearDown(self):
+        pass
+
+    def test_request(self):
+        req_json = json_from_file("./test/placement-tests/request.json")
+        policies = pol.get_local_policies("test/policy-local-files/", self.lp)
+        conductor.request(req_json, self.osdf_config, policies)
+
+
+if __name__ == "__main__":
+    unittest.main()
+
diff --git a/test/functest/scripts/sanity-check-simulators.sh b/test/functest/scripts/sanity-check-simulators.sh
new file mode 100644 (file)
index 0000000..93c5372
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+for x in policy has-api so-callback; do
+   curl http://localhost:5000/simulated/healthy/$x
+   curl http://localhost:5000/simulated/unhealthy/$x
+   curl http://localhost:5000/simulated/ERROR/$x
+   curl http://localhost:5000/simulated/success/$x
+done
+
+curl -d '{"A1": "B1"}' http://localhost:5000/simulated/policy/pdp-has-vcpe-good/getConfig
+curl -d '{"A1": "B1"}' http://localhost:5000/simulated/oof/has-api/flow1-success-simple/main.json
diff --git a/test/functest/scripts/start-simulators.sh b/test/functest/scripts/start-simulators.sh
new file mode 100755 (executable)
index 0000000..11767e0
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+#   Copyright (c) 2015-2017 AT&T Intellectual Property
+#
+#   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.
+#
+# -------------------------------------------------------------------------
+#
+
+# This script is in osdf/test/functest/scripts/
+
+SCRIPTDIR=$(dirname $(readlink -f $0))
+FUNC_TEST_DIR=$(dirname $SCRIPTDIR)
+TEST_DIR=$(dirname $FUNC_TEST_DIR)
+OSDF_DIR=$(dirname $TEST_DIR)
+SIMULATORS_DIR=$FUNC_TEST_DIR/simulators
+
+# Copy policy files from $TEST_DIR/policy-local-files into $SIMULATORS_DIR/policy/response-payloads
+(
+    cd $SIMULATORS_DIR
+    cp $TEST_DIR/policy-local-files/*.json $SIMULATORS_DIR/policy/response-payloads/pdp-has-vcpe-good
+)
+
+
+# start the flask application after linking the code location and config folder
+(
+    cd $SIMULATORS_DIR
+    ln -s $OSDF_DIR/osdf .
+    ln -s $SIMULATORS_DIR/simulated-config config
+
+    XPID=$(ps -x | grep "python oof_dependencies_simulators.py" | grep -v grep | awk '{print $1}')
+    if [ -z "$XPID" ]; then
+      python oof_dependencies_simulators.py > simulator-logs 2>&1 &
+      sleep 5
+    fi
+) 
+
+
+
diff --git a/test/functest/scripts/stop-simulators.sh b/test/functest/scripts/stop-simulators.sh
new file mode 100755 (executable)
index 0000000..c9dd126
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# -------------------------------------------------------------------------
+#   Copyright (c) 2015-2017 AT&T Intellectual Property
+#
+#   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.
+#
+# -------------------------------------------------------------------------
+#
+
+# This script is in osdf/test/functest/scripts/
+
+# We don't need all the directory names here and the "cd", but it may be needed later on
+# Also, it will be a guard against some bad config where the directory doesn't exist
+
+SCRIPTDIR=$(dirname $(readlink -f $0))
+FUNC_TEST_DIR=$(dirname $SCRIPTDIR)
+TEST_DIR=$(dirname $FUNC_TEST_DIR)
+OSDF_DIR=$(dirname $TEST_DIR)
+SIMULATORS_DIR=$FUNC_TEST_DIR/simulators
+
+cd $SIMULATORS_DIR
+
+XPID=$(ps -x | grep "python oof_dependencies_simulators.py" | grep -v grep | awk '{print $1}')
+if [ -n "$XPID" ]; then
+  kill $XPID
+fi
diff --git a/test/functest/simulators/has-api/response-payloads/flow1-success-simple/main.json b/test/functest/simulators/has-api/response-payloads/flow1-success-simple/main.json
new file mode 100644 (file)
index 0000000..a56840a
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "status": "template",
+  "name": "Plan Name 1",
+  "links": [
+    [
+      {
+        "href": "http://localhost:5000/simulated/oof/has-api/flow1-success-simple/status-solving.json",
+        "rel": "self"
+      }
+    ]
+  ],
+  "id": "plan_id"
+}
diff --git a/test/functest/simulators/has-api/response-payloads/flow1-success-simple/status-done.json b/test/functest/simulators/has-api/response-payloads/flow1-success-simple/status-done.json
new file mode 100644 (file)
index 0000000..3944b8c
--- /dev/null
@@ -0,0 +1,64 @@
+{
+  "plans": [
+    {
+      "status": "done",
+      "id": "plan_id",
+      "name": "Plan Name 1",
+      "links": [
+        [
+          {
+            "href": "http://conductor:8091/v1/plans/plan_id",
+            "rel": "self"
+          }
+        ]
+      ],
+      "recommendations": [
+        {
+          "vG": {
+            "inventory_provider": "aai",
+            "candidate": {
+              "candidate_id": "DLLSTX1A",
+              "cloud_owner": "CloudOwner1",
+              "inventory_type": "cloud",
+              "location_id": "DLLSTX1A",
+              "location_type": "openstack-cloud"
+            },
+            "attributes": {
+              "flavors": {
+                "flavor_label_1": "vim_flavor_X",
+                "flavor_label_2": "vim_flavor_Y"
+              },
+              "cloud_owner": "CloudOwner1",
+              "physical-location-id": "DLLSTX1A",
+              "cloud_version": "3.0",
+              "vim-id": "CloudOwner1_DLLSTX1A"
+            }
+          }
+        },
+        {
+          "vGMuxInfra": {
+            "attributes": {
+              "host_id": "vgmux_host_name",
+              "cloud_owner": "CloudOwner1",
+              "physical-location-id": "DLLSTX1A",
+              "service_instance_id": "21d5f3e8-e714-4383-8f99-cc480144505a",
+              "cloud_version": "3.0",
+              "vim-id": "CloudOwner1_DLLSTX1A"
+            },
+            "inventory_provider": "aai",
+            "service_resource_id": "12345",
+            "candidate": {
+              "is_rehome": "false",
+              "location_id": "DLLSTX1A",
+              "inventory_type": "service",
+              "candidate_id": "21d5f3e8-e714-4383-8f99-cc480144505a",
+              "host_id": "vgmux_host_name",
+              "cloud_owner": "CloudOwner1",
+              "location_type": "openstack-cloud"
+            }
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/functest/simulators/has-api/response-payloads/flow1-success-simple/status-solving.json b/test/functest/simulators/has-api/response-payloads/flow1-success-simple/status-solving.json
new file mode 100644 (file)
index 0000000..8bb074f
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "plans": [
+    {
+      "status": "solving",
+      "name": "Plan Name 1",
+      "links": [
+        [
+          {
+            "href": "http://localhost:5000/simulated/oof/has-api/flow1-success-simple/status-done.json",
+            "rel": "self"
+          }
+        ]
+      ],
+      "id": "plan_id"
+    }
+  ]
+}
diff --git a/test/functest/simulators/has-api/response-payloads/flow2-error-right-away/main.json b/test/functest/simulators/has-api/response-payloads/flow2-error-right-away/main.json
new file mode 100644 (file)
index 0000000..95a9750
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "plans": [
+    {
+      "status": "error",
+      "message": "Some error message",
+      "name": "Plan Name 1",
+      "links": [
+        [
+          {
+            "href": "http://conductor:8091/v1/plans/plan_id",
+            "rel": "self"
+          }
+        ]
+      ],
+      "id": "plan_id"
+    }
+  ]
+}
diff --git a/test/functest/simulators/has-api/response-payloads/orig/README.md b/test/functest/simulators/has-api/response-payloads/orig/README.md
new file mode 100644 (file)
index 0000000..212be9c
--- /dev/null
@@ -0,0 +1,2 @@
+Policies from HAS page: https://wiki.onap.org/display/DW/vCPE+Homing+Use+Case
+Retrieved 2018-03-28
diff --git a/test/functest/simulators/has-api/response-payloads/orig/status-done.json b/test/functest/simulators/has-api/response-payloads/orig/status-done.json
new file mode 100644 (file)
index 0000000..3944b8c
--- /dev/null
@@ -0,0 +1,64 @@
+{
+  "plans": [
+    {
+      "status": "done",
+      "id": "plan_id",
+      "name": "Plan Name 1",
+      "links": [
+        [
+          {
+            "href": "http://conductor:8091/v1/plans/plan_id",
+            "rel": "self"
+          }
+        ]
+      ],
+      "recommendations": [
+        {
+          "vG": {
+            "inventory_provider": "aai",
+            "candidate": {
+              "candidate_id": "DLLSTX1A",
+              "cloud_owner": "CloudOwner1",
+              "inventory_type": "cloud",
+              "location_id": "DLLSTX1A",
+              "location_type": "openstack-cloud"
+            },
+            "attributes": {
+              "flavors": {
+                "flavor_label_1": "vim_flavor_X",
+                "flavor_label_2": "vim_flavor_Y"
+              },
+              "cloud_owner": "CloudOwner1",
+              "physical-location-id": "DLLSTX1A",
+              "cloud_version": "3.0",
+              "vim-id": "CloudOwner1_DLLSTX1A"
+            }
+          }
+        },
+        {
+          "vGMuxInfra": {
+            "attributes": {
+              "host_id": "vgmux_host_name",
+              "cloud_owner": "CloudOwner1",
+              "physical-location-id": "DLLSTX1A",
+              "service_instance_id": "21d5f3e8-e714-4383-8f99-cc480144505a",
+              "cloud_version": "3.0",
+              "vim-id": "CloudOwner1_DLLSTX1A"
+            },
+            "inventory_provider": "aai",
+            "service_resource_id": "12345",
+            "candidate": {
+              "is_rehome": "false",
+              "location_id": "DLLSTX1A",
+              "inventory_type": "service",
+              "candidate_id": "21d5f3e8-e714-4383-8f99-cc480144505a",
+              "host_id": "vgmux_host_name",
+              "cloud_owner": "CloudOwner1",
+              "location_type": "openstack-cloud"
+            }
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/functest/simulators/has-api/response-payloads/orig/status-error.json b/test/functest/simulators/has-api/response-payloads/orig/status-error.json
new file mode 100644 (file)
index 0000000..95a9750
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "plans": [
+    {
+      "status": "error",
+      "message": "Some error message",
+      "name": "Plan Name 1",
+      "links": [
+        [
+          {
+            "href": "http://conductor:8091/v1/plans/plan_id",
+            "rel": "self"
+          }
+        ]
+      ],
+      "id": "plan_id"
+    }
+  ]
+}
diff --git a/test/functest/simulators/has-api/response-payloads/orig/status-solving.json b/test/functest/simulators/has-api/response-payloads/orig/status-solving.json
new file mode 100644 (file)
index 0000000..7868830
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "plans": [
+    {
+      "status": "solving",
+      "name": "Plan Name 1",
+      "links": [
+        [
+          {
+            "href": "http://conductor:8091/v1/plans/plan_id",
+            "rel": "self"
+          }
+        ]
+      ],
+      "id": "plan_id"
+    }
+  ]
+}
diff --git a/test/functest/simulators/has-api/response-payloads/orig/status-template.json b/test/functest/simulators/has-api/response-payloads/orig/status-template.json
new file mode 100644 (file)
index 0000000..6f20309
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "status": "template",
+  "name": "Plan Name 1",
+  "links": [
+    [
+      {
+        "href": "http://conductor:8091/v1/plans/plan_id",
+        "rel": "self"
+      }
+    ]
+  ],
+  "id": "plan_id"
+}
diff --git a/test/functest/simulators/oof_dependencies_simulators.py b/test/functest/simulators/oof_dependencies_simulators.py
new file mode 100755 (executable)
index 0000000..bdb552d
--- /dev/null
@@ -0,0 +1,84 @@
+# -------------------------------------------------------------------------
+#   Copyright (c) 2018 AT&T Intellectual Property
+#
+#   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.
+#
+# -------------------------------------------------------------------------
+#
+
+"""
+Simulators for dependencies of OSDF (e.g. HAS-API, Policy, SO-callback, etc.)
+"""
+import glob
+
+from osdf.utils.interfaces import json_from_file
+from flask import Flask, jsonify, request
+
+app = Flask(__name__)
+
+
+@app.route("/simulated/ERROR/<component>", methods=["GET", "POST"])
+@app.route("/simulated/unhealthy/<component>", methods=["GET", "POST"])
+def error_for_component(component):
+    """Send an HTTP error for component"""
+    return jsonify({"error": "{} error".format(component)}), 503
+
+
+@app.route("/simulated/healthy/<component>", methods=["GET", "POST"])
+def healthy_status_for_component(component):
+    """Send a health-OK response for component"""
+    return jsonify({"success": "Passed Health Check for Component {}".format(component)})
+
+
+@app.route("/simulated/success/<component>", methods=["GET", "POST"])
+def successful_call_for_component(component):
+    """Send a message about successful call to component"""
+    return jsonify({"success": "made a call to Component: {}".format(component)})
+
+
+@app.route("/simulated/oof/has-api/<path:mainpath>", methods=["GET", "POST"])
+def has_api_calls(mainpath):
+    data, status = get_payload_for_simulated_component('has-api', mainpath)
+    if not status:
+        return jsonify(data)
+    return jsonify(data), 503
+
+
+def get_payload_for_simulated_component(component, mainpath):
+    """
+    Get the payload for the given path for the given component
+    :param component: Component we are using (e.g. HAS-API, Policy, SO-callback, etc.)
+    :param mainpath: path within the URL (e.g. /main/X1/y1/)
+    :return: Content if file exists, or else 503 error
+    """
+    file_name = "{}/response-payloads/{}".format(component, mainpath)
+    data = json_from_file(file_name)
+    if not data:
+        return {"Error": "Unable to read File {}".format(file_name)}, 503
+    return data, None
+
+
+@app.route("/simulated/policy/<sub_component>/getConfig", methods=["POST"])
+def get_policies(sub_component):
+    """
+    Get all policies for this folder
+    :param sub_component: The folder we are interested in (e.g. "pdp-has-vcpe-good", "pdp-has-vcpe-bad")
+    :return: A list of policies as a json object (each element is one policy)
+    """
+    main_dir = "policy/response-payloads/" + sub_component
+    files = glob.glob("{}/*.json".format(main_dir))
+    return jsonify([json_from_file(x) for x in files])
+
+
+if __name__ == "__main__":
+    app.run(debug=True)
diff --git a/test/functest/simulators/policy/response-payloads/README.md b/test/functest/simulators/policy/response-payloads/README.md
new file mode 100644 (file)
index 0000000..2ae3965
--- /dev/null
@@ -0,0 +1 @@
+All policy local files will come here
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Affinity_vCPE_1.json
new file mode 100644 (file)
index 0000000..4a3e086
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "service": "affinityPolicy",
+    "policyName": "oofBeijing.affinityPolicy_vcpe",
+    "description": "Affinity policy for vCPE",
+    "templateVersion": "1702.03",
+    "version": "oofBeijing",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+        "identity": "affinity_vCPE",
+        "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"],
+        "affinityProperty": {
+            "qualifier": "different",
+            "category": "complex"
+        },
+        "policyType": "zone",
+        "resources": ["vGMuxInfra", "vG"],
+        "applicableResources": "all"
+    }
+}
\ No newline at end of file
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vGMuxInfra.json
new file mode 100644 (file)
index 0000000..0225d40
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "service": "capacityPolicy",
+    "policyName": "oofBeijing.capacityPolicy_vGMuxInfra",
+    "description": "Capacity policy for vGMuxInfra",
+    "templateVersion": "1702.03",
+    "version": "oofBeijing",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+        "identity": "capacity_vGMuxInfra",
+        "policyScope": ["VCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vim_fit"],
+           "resources": ["vGMuxInfra"],
+        "capacityProperty": {
+            "controller": "multicloud",
+            "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": 16, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": 40, \"unit\": \"GB\"}}"
+        },
+        "policyType": "vim_fit",
+        "applicableResources": "any"
+    }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Capacity_vG_1.json
new file mode 100644 (file)
index 0000000..f311650
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "service": "capacityPolicy",
+    "policyName": "oofBeijing.capacityPolicy_vG",
+    "description": "Capacity policy for vG",
+    "templateVersion": "1702.03",
+    "version": "oofBeijing",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+        "identity": "capacity_vG",
+        "policyScope": ["VCPE", "US", "INTERNATIONAL", "ip", "vG", "vim_fit"],
+           "resources": ["vG"],
+        "capacityProperty": {
+            "controller": "multicloud",
+            "request": "{\"vCPU\": 10, \"Memory\": {\"quantity\": 16, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": 40, \"unit\": \"GB\"}}"
+        },
+        "policyType": "vim_fit",
+        "applicableResources": "any"
+    }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vGMuxInfra_1.json
new file mode 100644 (file)
index 0000000..992e9ec
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "service": "distancePolicy",
+  "policyName": "oofBeijing.distancePolicy_vGMuxInfra",
+  "description": "Distance Policy for vGMuxInfra",
+  "templateVersion": "0.0.1",
+  "version": "oofBeijing",
+  "priority": "3",
+  "riskType": "test",
+  "riskLevel": "2",
+  "guard": "False",
+  "content": {
+    "distanceProperties": {
+      "locationInfo": "customer_location",
+      "distance": { "value": "500", "operator": "<", "unit": "km" }
+    },
+    "identity": "distance-vGMuxInfra",
+    "resources": ["vGMuxInfra"],
+    "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "distancePolicy"],
+    "policyType": "distance_to_location",
+    "applicableResources": "any"
+  }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Distance_vG_1.json
new file mode 100644 (file)
index 0000000..07baabd
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "service": "distancePolicy",
+  "policyName": "oofBeijing.distancePolicy_vG",
+  "description": "Distance Policy for vG",
+  "templateVersion": "0.0.1",
+  "version": "oofBeijing",
+  "priority": "3",
+  "riskType": "test",
+  "riskLevel": "2",
+  "guard": "False",
+  "content": {
+    "distanceProperties": {
+      "locationInfo": "customer_location",
+      "distance": { "value": "1500", "operator": "<", "unit": "km" }
+    },
+    "identity": "distance-vG",
+    "resources": ["vG"],
+    "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG", "distancePolicy"],
+    "policyType": "distance_to_location",
+    "applicableResources": "any"
+  }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/Placement_Optimization_1.json
new file mode 100644 (file)
index 0000000..6d09b82
--- /dev/null
@@ -0,0 +1,36 @@
+{
+    "service": "PlacementOptimizationPolicy",
+    "policyName": "oofBeijing.PlacementOptimizationPolicy_vGMuxInfra",
+    "description": "Placement Optimization Policy for vGMuxInfra",
+    "templateVersion": "1702.03",
+    "version": "oofBeijing",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "objectiveParameter": {
+            "parameterAttributes": [
+                {
+                    "resources": ["vGMuxInfra"],
+                    "customerLocationInfo": "customer_loc",
+                    "parameter": "distance",
+                    "weight": "1",
+                    "operator": "product"
+                },
+                {
+                    "resources": ["vG"],
+                    "customerLocationInfo": "customer_loc",
+                    "parameter": "distance",
+                    "weight": "1",
+                    "operator": "product"
+                }
+            ],
+            "operator": "sum"
+        },
+        "identity": "optimization",
+        "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG", "placementOptimization"],
+        "policyType": "placementOptimization",
+        "objective": "minimize"
+    }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE.json
new file mode 100644 (file)
index 0000000..03c457e
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  "service": "optimizationQueryPolicy",
+  "policyName": "oofBeijing.queryPolicy_vCPE",
+  "description": "Optimization query policy for vCPE",
+  "templateVersion": "0.0.1",
+  "version": "oofBeijing",
+  "priority": "3",
+  "riskType": "test",
+  "riskLevel": "2",
+  "guard": "False",
+  "content": {
+    "queryProperties": [
+      {"attribute":"locationId", "attribute_location": "customerLocation", "value": ""},
+      {"attribute":"id", "attribute_location": "vpnInfo.vpnId", "value": ""},
+      {"attribute":"upstreamBW", "attribute_location": "vpnInfo.upstreamBW", "value": ""},
+      {"attribute":"customerLatitude", "attribute_location": "customerLatitude", "value": 32.89748},
+      {"attribute":"customerLongitude", "attribute_location": "customerLongitude", "value": -97.040443}
+    ],
+    "serviceName": "vCPE",
+    "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG", "optimizationQueryPolicy"],
+    "policyType": "optimizationQueryPolicy"
+  }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/QueryPolicy_vCPE_2.json
new file mode 100644 (file)
index 0000000..7f1db83
--- /dev/null
@@ -0,0 +1,23 @@
+{
+  "service": "optimizationQueryPolicy",
+  "policyName": "oofBeijing.queryPolicy_vCPE",
+  "description": "Optimization query policy for vCPE",
+  "templateVersion": "0.0.1",
+  "version": "oofBeijing",
+  "priority": "5",
+  "riskType": "test",
+  "riskLevel": "2",
+  "guard": "False",
+  "content": {
+    "queryProperties": [
+      {"attribute":"locationId", "attribute_location": "customerLocation", "value": ""},
+      {"attribute":"id", "attribute_location": "vpnInfo.vpnId", "value": ""},
+      {"attribute":"upstreamBW", "attribute_location": "vpnInfo.upstreamBW", "value": ""},
+      {"attribute":"customerLatitude", "attribute_location": "customerLatitude", "value": 1.1},
+      {"attribute":"customerLongitude", "attribute_location": "customerLongitude", "value": 2.2}
+    ],
+    "serviceName": "vCPE",
+    "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG", "optimizationQueryPolicy"],
+    "policyType": "optimizationQueryPolicy"
+  }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/README.md b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/README.md
new file mode 100644 (file)
index 0000000..58c5cb5
--- /dev/null
@@ -0,0 +1 @@
+All HAS-related policy local files will come here
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vGMuxInfra_1.json
new file mode 100644 (file)
index 0000000..a3403f0
--- /dev/null
@@ -0,0 +1,144 @@
+{
+    "service": "hpaPolicy",
+    "policyName": "oofBeijing.hpaPolicy_vGMuxInfra",
+    "description": "HPA policy for vGMuxInfra",
+    "templateVersion": "0.0.1",
+    "version": "1.0",
+    "priority": "3",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+      "resources": ["vGMuxInfra"],
+      "identity": "hpaPolicy_vGMuxInfra",
+      "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "hpaPolicy"],
+      "policyType": "hpa",
+      "flavorFeatures": [
+        {
+          "flavorLabel": "flavor_label_vm_01",
+          "flavorProperties":[
+            {
+              "hpa-feature" : "cpuTopology",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "2","operator": ">=", "unit": ""},
+                {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "4","operator": "<=", "unit": ""},
+                {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "2", "operator":">=", "unit": ""},
+                {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "4", "operator":"<=", "unit": ""},
+                {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "4", "operator":">=", "unit": ""},
+                {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "8", "operator":"<=", "unit": ""}
+              ]
+            },
+            {
+              "hpa-feature" : "basicCapabilities",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+              ]
+            },
+            {
+              "hpa-feature" : "ovsDpdk",
+              "mandatory" : "False",
+              "score" : "3",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                 {"hpa-attribute-key":"dataProcessingAccelerationLibrary", "hpa-attribute-value":"ovsDpdk_version", "operator": "=", "unit":""}
+              ]
+            },
+            {
+              "hpa-feature" : "cpuInstructionSetExtensions",
+              "mandatory" : "True",
+              "architecture": "INTEL-64",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key":"instructionSetExtensions", "hpa-attribute-value":["<CPUINST>", "<CPUINST>"], "operator": "ALL", "unit":""}
+              ]
+            }
+          ]
+        },
+        {
+          "flavorLabel": "flavor_label_vm_02",
+          "flavorProperties":[
+            {
+              "hpa-feature" : "cpuPinningy",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key":"logicalCpuThreadPinningPolicy", "hpa-attribute-value":"<CPUTHREADPOLICY>", "operator": "=", "unit":""},
+                {"hpa-attribute-key":"logicalCpuPinningPolicy", "hpa-attribute-value": "<CPUPOLICY>","operator": "=", "unit":""}
+              ]
+            },
+            {
+              "hpa-feature" : "basicCapabilities",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+              ]
+            },
+            {
+              "hpa-feature" : "localStorage",
+              "mandatory" : "False",
+              "score" : "5",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "diskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},
+                {"hpa-attribute-key": "ephemeralDiskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},
+                {"hpa-attribute-key": "swapMemSize", "hpa-attribute-value":"16", "operator": "=", "unit": "MB"}
+              ]
+            },
+            {
+              "hpa-feature" : "pcie",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "pciCount", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "pciVendorId", "hpa-attribute-value":"8086", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "pciDeviceId", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "functionType", "hpa-attribute-value": "<PCITYPEVALUE>","operator": "=", "unit": ""}
+              ]
+            }
+          ]
+        },
+        {
+          "flavorLabel": "flavor_label_vm_03",
+          "flavorProperties":[
+            {
+              "hpa-feature" : "numa",
+              "mandatory" : "False",
+              "score" : "5",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numaNodes", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "numaCpu-0", "hpa-attribute-value":"2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "numaMem-0", "hpa-attribute-value": "2048", "operator": "=", "unit": "MB"},
+                {"hpa-attribute-key": "numaCpu-1", "hpa-attribute-value":"4", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "numaMem-1", "value": "4096", "operator": "=", "unit": "MB"}
+              ]
+            },
+            {
+              "hpa-feature" : "basicCapabilities",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+              ]
+            },
+            {
+              "hpa-feature" : "hugePages",
+              "mandatory" : "False",
+              "score" : "7",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                 {"hpa-attribute-key": "memoryPageSize", "hpa-attribute-value": "<MEMORYPAGESIZE>", "operator": "=", "unit": ""}
+              ]
+            }
+          ]
+        }
+      ]
+    }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/hpa_policy_vG_1.json
new file mode 100644 (file)
index 0000000..9b832f6
--- /dev/null
@@ -0,0 +1,144 @@
+{
+    "service": "hpaPolicy",
+    "policyName": "oofBeijing.hpaPolicy_vG",
+    "description": "HPA policy for vG",
+    "templateVersion": "0.0.1",
+    "version": "1.0",
+    "priority": "3",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+      "resources": ["vG"],
+      "identity": "hpaPolicy_vG",
+      "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vG", "hpaPolicy"],
+      "policyType": "hpa",
+      "flavorFeatures": [
+        {
+          "flavorLabel": "flavor_label_vm_01",
+          "flavorProperties":[
+            {
+              "hpa-feature" : "cpuTopology",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "2","operator": ">=", "unit": ""},
+                {"hpa-attribute-key":"numCpuSockets", "hpa-attribute-value": "4","operator": "<=", "unit": ""},
+                {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "2", "operator":">=", "unit": ""},
+                {"hpa-attribute-key":"numCpuCores", "hpa-attribute-value": "4", "operator":"<=", "unit": ""},
+                {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "4", "operator":">=", "unit": ""},
+                {"hpa-attribute-key":"numCpuThreads", "hpa-attribute-value": "8", "operator":"<=", "unit": ""}
+              ]
+            },
+            {
+              "hpa-feature" : "basicCapabilities",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+              ]
+            },
+            {
+              "hpa-feature" : "ovsDpdk",
+              "mandatory" : "False",
+              "score" : "3",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                 {"hpa-attribute-key":"dataProcessingAccelerationLibrary", "hpa-attribute-value":"ovsDpdk_version", "operator": "=", "unit":""}
+              ]
+            },
+            {
+              "hpa-feature" : "cpuInstructionSetExtensions",
+              "mandatory" : "True",
+              "architecture": "INTEL-64",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key":"instructionSetExtensions", "hpa-attribute-value":["<CPUINST>", "<CPUINST>"], "operator": "ALL", "unit":""}
+              ]
+            }
+          ]
+        },
+        {
+          "flavorLabel": "flavor_label_vm_02",
+          "flavorProperties":[
+            {
+              "hpa-feature" : "cpuPinningy",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key":"logicalCpuThreadPinningPolicy", "hpa-attribute-value":"<CPUTHREADPOLICY>", "operator": "=", "unit":""},
+                {"hpa-attribute-key":"logicalCpuPinningPolicy", "hpa-attribute-value": "<CPUPOLICY>","operator": "=", "unit":""}
+              ]
+            },
+            {
+              "hpa-feature" : "basicCapabilities",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+              ]
+            },
+            {
+              "hpa-feature" : "localStorage",
+              "mandatory" : "False",
+              "score" : "5",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "diskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},  
+                {"hpa-attribute-key": "ephemeralDiskSize", "hpa-attribute-value": "2", "operator": "=", "unit": "GB"},
+                {"hpa-attribute-key": "swapMemSize", "hpa-attribute-value":"16", "operator": "=", "unit": "MB"}
+              ]
+            },
+            {
+              "hpa-feature" : "pcie",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "pciCount", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "pciVendorId", "hpa-attribute-value":"8086", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "pciDeviceId", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "functionType", "hpa-attribute-value": "<PCITYPEVALUE>","operator": "=", "unit": ""}
+              ]
+            }
+          ]
+        },
+        {
+          "flavorLabel": "flavor_label_vm_03",
+          "flavorProperties":[
+            {
+              "hpa-feature" : "numa",
+              "mandatory" : "False",
+              "score" : "5",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numaNodes", "hpa-attribute-value": "2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "numaCpu-0", "hpa-attribute-value":"2", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "numaMem-0", "hpa-attribute-value": "2048", "operator": "=", "unit": "MB"},
+                {"hpa-attribute-key": "numaCpu-1", "hpa-attribute-value":"4", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "numaMem-1", "value": "4096", "operator": "=", "unit": "MB"}
+              ]
+            },
+            {
+              "hpa-feature" : "basicCapabilities",
+              "mandatory" : "True",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                {"hpa-attribute-key": "numVirtualCpu", "hpa-attribute-value": "6", "operator": "=", "unit": ""},
+                {"hpa-attribute-key": "virtualMemSize", "hpa-attribute-value":"6", "operator": "=", "unit": "GB"}
+              ]
+            },
+            {
+              "hpa-feature" : "hugePages",
+              "mandatory" : "False",
+              "score" : "7",
+              "architecture": "generic",
+              "hpa-feature-attributes": [
+                 {"hpa-attribute-key": "memoryPageSize", "hpa-attribute-value": "<MEMORYPAGESIZE>", "operator": "=", "unit": ""}
+              ]
+            }
+          ]
+        }
+      ]
+    }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/subscriber_policy.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/subscriber_policy.json
new file mode 100644 (file)
index 0000000..f1b818c
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "service": "SubscriberPolicy",
+    "policyName": "oofBeijing.SubscriberPolicy_v1",
+    "description": "Subscriber Policy",
+    "templateVersion": "0.0.1",
+    "version": "oofBeijing",
+    "priority": "1",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "subscriber",
+        "policyScope": ["vCPE", "subscriber_x", "subscriber_y", "subscriberPolicy"],
+        "properties": {
+                "subscriberName": ["subscriber_x", "subscriber_y"],
+                "subscriberRole": ["PVT Homing"],
+                "provStatus": ["CAPPED"]
+        },
+        "policyType": "subscriberPolicy",
+        "serviceName": "vCPE"
+    }
+}
\ No newline at end of file
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vG.json
new file mode 100644 (file)
index 0000000..c77cdc7
--- /dev/null
@@ -0,0 +1,32 @@
+{
+    "service": "VnfPolicy",
+    "policyName": "oofBeijing.vnfPolicy_vG",
+    "description": "vnfPolicy",
+    "templateVersion": "1702.03",
+    "version": "oofBeijing",
+    "priority": "6",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vnf_vG",
+        "policyScope": ["vCPE", "INTERNATIONAL", "ip", "vG", "vnf_policy"],
+        "policyType": "vnfPolicy",
+        "resources": ["vG"],
+        "applicableResources": "any",
+           "vnfProperties": [
+            {
+                "inventoryProvider": "aai",
+                "serviceType": "",
+                "inventoryType": "cloud",
+                "customerId": ""
+            },
+            {
+                "inventoryProvider": "multicloud",
+                "serviceType": "HNGATEWAY",
+                "inventoryType": "service",
+                "customerId": "21014aa2-526b-11e6-beb8-9e71128cae77"
+            }
+        ]
+    }
+}
diff --git a/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json b/test/functest/simulators/policy/response-payloads/pdp-has-vcpe-good/vnfPolicy_vGMuxInfra.json
new file mode 100644 (file)
index 0000000..3971519
--- /dev/null
@@ -0,0 +1,32 @@
+{
+    "service": "VnfPolicy",
+    "policyName": "oofBeijing.vnfPolicy_vGMuxInfra",
+    "description": "vnfPolicy",
+    "templateVersion": "1702.03",
+    "version": "oofBeijing",
+    "priority": "6",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vnf_vGMuxInfra",
+        "policyScope": ["vCPE", "INTERNATIONAL", "ip", "vGMuxInfra", "vnf_policy"],
+        "policyType": "vnfPolicy",
+        "resources": ["vGMuxInfra"],
+        "applicableResources": "any",
+       "vnfProperties": [
+            {
+                "inventoryProvider": "aai",
+                "serviceType": "",
+                "inventoryType": "cloud",
+                "customerId": ""
+            },
+            {
+                "inventoryProvider": "multicloud",
+                "serviceType": "HNGATEWAY",
+                "inventoryType": "service",
+                "customerId": "21014aa2-526b-11e6-beb8-9e71128cae77"
+            }
+        ]
+    }
+}
diff --git a/test/functest/simulators/simulated-config/common_config.yaml b/test/functest/simulators/simulated-config/common_config.yaml
new file mode 100644 (file)
index 0000000..770fef2
--- /dev/null
@@ -0,0 +1,63 @@
+osdf_system:
+    libpath: /opt/app/osdf/libs
+    osdf_ports:
+        internal: 8699  # inside the Docker container, the app listens to this port
+        external: 8698  # clients use this port on DockerHost
+    osdf_ip_default: 0.0.0.0
+#        # Important Note: At deployment time, we need to ensure the port mapping is done
+#    ssl_context: ['./../etc/sniromanager.crt', './../etc/sniromanager.key']
+
+osdf_temp:  # special configuration required for "workarounds" or testing
+    local_policies:
+        global_disabled: True
+        local_placement_policies_enabled: True
+        placement_policy_files_vcpe: # workaroud for policy platform glitches (or "work-arounds" for other components)
+            - Affinity_vCPE_1.json
+            - Capacity_vGMuxInfra.json
+            - Capacity_vG_1.json
+            - Distance_vGMuxInfra_1.json
+            - Distance_vG_1.json
+            - Placement_Optimization_1.json
+            - QueryPolicy_vCPE.json
+            - hpa_policy_vGMuxInfra_1.json
+            - hpa_policy_vG_1.json
+            - vnfPolicy_vG.json
+            - vnfPolicy_vGMuxInfra.json
+service_info:
+    vCPE:
+        vcpeHostName: requestParameters.vcpeHostName
+        e2eVpnKey: requestParameters.e2eVpnKey
+
+references:
+    service_name:
+        source: request
+        value: serviceInfo.serviceName
+    subscriber_role:
+        source: SubscriberPolicy
+        value: content.properties.subscriberRole
+
+policy_info:
+    prioritization_attributes:
+        policy_type:
+            - content.policyType
+        resources:
+            - content.resources
+            - content.objectiveParameter.parameterAttributes.resources
+        service_name:
+            - content.serviceName
+
+    placement:
+        policy_fetch: by_scope
+        policy_scope:
+            default_scope: OSDF_R2
+            vcpe_scope: OSDF_R2
+            secondary_scopes:
+                -
+                    - get_param: service_name
+                    - SubscriberPolicy
+                -
+                    - get_param: service_name
+                    - get_param: subscriber_role
+    default:  # if no explicit service related information is needed
+        policy_fetch: by_name
+        policy_scope: none
diff --git a/test/functest/simulators/simulated-config/has_config.yaml b/test/functest/simulators/simulated-config/has_config.yaml
new file mode 100644 (file)
index 0000000..8cbeda2
--- /dev/null
@@ -0,0 +1,24 @@
+policy_config_mapping:
+    attributes:
+        hypervisor: hypervisor,
+        cloud_version: cloudVersion,
+        cloud_type: cloudType,
+        dataplane: dataPlane,
+        network_roles: networkRoles,
+        complex: complex,
+        state: state,
+        country: country,
+        geo_region: geoRegion,
+        exclusivity_groups: exclusivityGroups,
+        replication_role: replicationRole,
+    remapping:
+        model-invariant-id: modelInvariantId,
+        model-version-id: modelVersionId
+    candidates:
+        # for (k1, v1), if k1 is in demand, set prop[k2] = _get_candidates(demand[k1])
+        exclusionCandidateInfo: excluded_candidates,
+        requiredCandidateInfo: required_candidates
+    extra_fields:
+        # we have [k1, k2, k3, k4] type items and x is policy-content-properties
+        # if x[k1] == k2: set prop[k3] = k4
+        - [inventoryType, cloud, region, {get_param: CHOSEN_REGION}]
\ No newline at end of file
diff --git a/test/functest/simulators/simulated-config/osdf_config.yaml b/test/functest/simulators/simulated-config/osdf_config.yaml
new file mode 100755 (executable)
index 0000000..a192b70
--- /dev/null
@@ -0,0 +1,34 @@
+osdfUserNameForSO: ""   # The OSDF Manager username for MSO.
+odfPasswordForSO: ""   # The OSDF Manager password for MSO.
+
+# msoUrl: ""   # The SO url for call back. This will be part of the request, so no need
+soUsername: ""   # SO username for call back.
+soPassword: ""   # SO password for call back.
+
+conductorUrl: "http://localhost:5000/simulated/oof/has-api/flow1-success-simple/main.json"
+conductorUsername: "CONDUCTOR-USER"
+conductorPassword: "CONDUCTOR-PASSWD"
+conductorPingWaitTime: 2  # seconds to wait before calling the conductor retry URL
+conductorMaxRetries: 5  # if we don't get something in 30 minutes, give up
+
+# Policy Platform -- requires ClientAuth, Authorization, and Environment
+policyPlatformUrl: http://localhost:5001/simulated/policy/pdp-has-vcpe-good/pdp/getConfig # Policy Dev platform URL
+policyPlatformEnv: TEST  # Environment for policy platform
+policyPlatformUsername: POLICY-USER   # Policy platform username.
+policyPlatformPassword: POLICY-PASSWD   # Policy platform password.
+policyClientUsername: POLICY-CLIENT-USER   # For use with ClientAuth
+policyClientPassword: POLICY-CLIENT-PASSWD   # For use with ClientAuth
+
+messageReaderHosts: https://DMAAP-HOST1:3905,https://DMAAP-HOST2:3905,https://DMAAP-HOST3:3905
+messageReaderTopic: org.onap.oof.osdf.multicloud
+messageReaderAafUserId: DMAAP-OSDF-MC-USER
+messageReaderAafPassword: DMAAP-OSDF-MC-PASSWD
+
+sdcUrl: https://SDC-HOST:8443/sdc/v1/catalog
+sdcUsername: SDC-OSDF-USER
+sdcPassword: SDC-OSDF-PASSWD
+sdcONAPInstanceID: ONAP-OSDF
+
+osdfPlacementUrl: "http://127.0.0.1:24699/osdf/api/v2/placement"
+osdfPlacementUsername: "test"
+osdfPlacementPassword: "testpwd"
diff --git a/test/functest/simulators/simulated-config/simulated-config b/test/functest/simulators/simulated-config/simulated-config
new file mode 120000 (symlink)
index 0000000..9c5a662
--- /dev/null
@@ -0,0 +1 @@
+/Users/sastry/PycharmProjects/osdf/test/functest/simulators/simulated-config
\ No newline at end of file
diff --git a/test/policy-local-files/has_policies_r2/meta-valid-policies.txt b/test/policy-local-files/has_policies_r2/meta-valid-policies.txt
deleted file mode 100644 (file)
index 6a22945..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Affinity_vCPE_1.json
-Capacity_1.json
-Distance_vGMuxInfra_1.json
-Distance_vG_1.json
-Min_Guarantee_vGMuxInfra_1.json
-Placement_Optimization_1.json
-QueryPolicy_vCPE.json
-hpa_policy_vGMuxInfra_1.json
-hpa_policy_vG_1.json
-subscriber_policy.json
-vnfPolicy_vG.json
-vnfPolicy_vGMuxInfra.json
-
-
index 30fc072..fef7574 100644 (file)
@@ -45,41 +45,32 @@ class TestPolicyCalls(unittest.TestCase):
     def tearDown(self):
         pass
 
+    def get_req_resp(self, req_file, resp_file):
+        """Get request/response from files"""
+        req_json = json_from_file(req_file)
+        resp_json = json_from_file(resp_file)
+        return req_json, resp_json
+
     def test_policy_api_call(self):
-        req_json_file = "./test/placement-tests/request.json"
-        req_json = json.loads(open(req_json_file).read())
-        policy_response_file = "./test/placement-tests/policy_response.json"
-        policy_response = json.loads(open(policy_response_file).read())
+        req_json, policy_response = self.get_req_resp("./test/placement-tests/request.json",
+                                                      "./test/placement-tests/policy_response.json")
         with patch('osdf.adapters.policy.interface.policy_api_call', return_value=policy_response):
             policy_list = interface.remote_api(req_json, osdf_config, service_type="placement")
             self.assertIsNotNone(policy_list)
 
-    def test_policy_api_call_failed_1(self):
-        req_json_file = "./test/placement-tests/request_error1.json"
-        req_json = json.loads(open(req_json_file).read())
-        policy_response_file = "./test/placement-tests/policy_response.json"
-        policy_response = json.loads(open(policy_response_file).read())
-        with patch('osdf.adapters.policy.interface.policy_api_call', return_value=policy_response):
-            self.assertRaises(BusinessException,
-                              lambda: interface.remote_api(req_json, osdf_config, service_type="placement"))
-
-    def test_policy_api_call_failed_2(self):
-        req_json_file = "./test/placement-tests/request.json"
-        req_json = json.loads(open(req_json_file).read())
-        policy_response_file = "./test/placement-tests/policy_response_error1.json"
-        policy_response = json.loads(open(policy_response_file).read())
+    def failure_policy_call(self, req_json_file, resp_json_file):
+        req_json, policy_response = self.get_req_resp(req_json_file, resp_json_file)
         with patch('osdf.adapters.policy.interface.policy_api_call', return_value=policy_response):
             self.assertRaises(BusinessException,
                               lambda: interface.remote_api(req_json, osdf_config, service_type="placement"))
 
-    def test_policy_api_call_failed_3(self):
-        req_json_file = "./test/placement-tests/request.json"
-        req_json = json.loads(open(req_json_file).read())
-        policy_response_file = "./test/placement-tests/policy_response_error2.json"
-        policy_response = json.loads(open(policy_response_file).read())
-        with patch('osdf.adapters.policy.interface.policy_api_call', return_value=policy_response):
-            self.assertRaises(BusinessException,
-                              lambda: interface.remote_api(req_json, osdf_config, service_type="placement"))
+    def test_policy_api_call_failed_multi(self):
+        prefix = "./test/placement-tests"
+        fail_cases = [("request_error1.json", "policy_response.json"),
+                      ("request.json", "policy_response_error1.json"),
+                      ("request.json", "policy_response_error2.json")]
+        for req, resp in fail_cases:
+            self.failure_policy_call(prefix + "/" + req, prefix + "/" + resp)
 
     def test_get_by_scope(self):
         req_json_file = "./test/placement-tests/testScoperequest.json"
@@ -110,5 +101,10 @@ class TestPolicyCalls(unittest.TestCase):
         self.assertListEqual(genDemandslist, actionsList, 'generated demands are not equal to the passed input'
                                                           '[placementDemand][resourceModuleName] list')
            
+    def test_local_policy_location(self):
+        req_json = json_from_file("./test/placement-tests/request.json")
+        return interface.local_policies_location(req_json, osdf_config, service_type="placement")
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tox.ini b/tox.ini
index cdb7381..18be307 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -6,9 +6,11 @@ envlist = py3
 [testenv]
 distribute = False
 commands =
+    /bin/bash test/functest/scripts/start-simulators.sh
     coverage run --module pytest --junitxml xunit-results.xml
     coverage xml --omit=".tox/py3/*","test/*"
     coverage report -m --omit=".tox/py3/*","test/*"
+    /bin/bash test/functest/scripts/stop-simulators.sh
     # TODO: need to update the above "omit" when we package osdf as pip-installable
 deps = -r{toxinidir}/requirements.txt 
     -r{toxinidir}/test/test-requirements.txt