Re-org folders, onboard test folder, test config 79/31279/1
authorAnkitkumar Patel <ankit@research.att.com>
Sun, 11 Feb 2018 22:51:13 +0000 (17:51 -0500)
committerAnkitkumar Patel <ankit@research.att.com>
Sun, 11 Feb 2018 22:52:51 +0000 (17:52 -0500)
Reorganized the folder structure. Onboarded testcases. Added test config.

Issue-ID: OPTFRA-74
Change-Id: I97882a162a405a18ffd287495039e15ae9d0ad7b
Signed-off-by: Ankitkumar Patel <ankit@research.att.com>
95 files changed:
.gitignore [new file with mode: 0644]
LICENSE.txt [new file with mode: 0644]
config/common_config.yaml [new file with mode: 0644]
config/osdf_config.yaml [new file with mode: 0755]
osdf/__init__.py [moved from __init__.py with 100% similarity]
osdf/adapters/__init__.py [moved from adapters/__init__.py with 100% similarity]
osdf/adapters/database/OracleDB.py [moved from adapters/database/OracleDB.py with 100% similarity]
osdf/adapters/database/PostgresDB.py [moved from adapters/database/PostgresDB.py with 100% similarity]
osdf/adapters/database/VerticaDB.py [moved from adapters/database/VerticaDB.py with 100% similarity]
osdf/adapters/database/__init__.py [moved from adapters/database/__init__.py with 100% similarity]
osdf/adapters/dcae/__init__.py [moved from adapters/dcae/__init__.py with 100% similarity]
osdf/adapters/dcae/message_router.py [moved from adapters/dcae/message_router.py with 100% similarity]
osdf/adapters/local_data/__init__.py [moved from adapters/local_data/__init__.py with 100% similarity]
osdf/adapters/local_data/local_policies.py [moved from adapters/local_data/local_policies.py with 100% similarity]
osdf/adapters/policy/__init__.py [moved from adapters/policy/__init__.py with 100% similarity]
osdf/adapters/policy/interface.py [moved from adapters/policy/interface.py with 97% similarity]
osdf/adapters/policy/utils.py [moved from adapters/policy/utils.py with 100% similarity]
osdf/adapters/request_parsing/__init__.py [moved from adapters/request_parsing/__init__.py with 100% similarity]
osdf/adapters/request_parsing/placement.py [moved from adapters/request_parsing/placement.py with 100% similarity]
osdf/adapters/sdc/__init__.py [moved from adapters/sdc/__init__.py with 100% similarity]
osdf/adapters/sdc/asdc.py [moved from adapters/sdc/asdc.py with 100% similarity]
osdf/adapters/sdc/constraint_handler.py [moved from adapters/sdc/constraint_handler.py with 100% similarity]
osdf/config/__init__.py [moved from config/__init__.py with 100% similarity]
osdf/config/base.py [moved from config/base.py with 100% similarity]
osdf/config/credentials.py [moved from config/credentials.py with 100% similarity]
osdf/config/loader.py [moved from config/loader.py with 100% similarity]
osdf/logging/__init__.py [moved from operation/__init__.py with 100% similarity]
osdf/logging/osdf_logging.py [new file with mode: 0755]
osdf/models/api/common.py [moved from models/api/common.py with 100% similarity]
osdf/models/api/placementRequest.py [moved from models/api/placementRequest.py with 100% similarity]
osdf/models/api/placementResponse.py [moved from models/api/placementResponse.py with 100% similarity]
osdf/models/policy/cmso/xacml/placementPolicies.xcore [moved from models/policy/cmso/xacml/placementPolicies.xcore with 100% similarity]
osdf/models/policy/placement/xacml/placementPolicies.xcore [moved from models/policy/placement/xacml/placementPolicies.xcore with 100% similarity]
osdf/operation/__init__.py [moved from optimizers/__init__.py with 100% similarity]
osdf/operation/error_handling.py [moved from operation/error_handling.py with 100% similarity]
osdf/operation/exceptions.py [moved from operation/exceptions.py with 100% similarity]
osdf/operation/responses.py [moved from operation/responses.py with 100% similarity]
osdf/optimizers/__init__.py [moved from optimizers/licenseopt/__init__.py with 100% similarity]
osdf/optimizers/licenseopt/__init__.py [moved from optimizers/placementopt/__init__.py with 100% similarity]
osdf/optimizers/licenseopt/simple_license_allocation.py [moved from optimizers/licenseopt/simple_license_allocation.py with 100% similarity]
osdf/optimizers/placementopt/__init__.py [moved from optimizers/placementopt/conductor/__init__.py with 100% similarity]
osdf/optimizers/placementopt/conductor/__init__.py [moved from utils/__init__.py with 100% similarity]
osdf/optimizers/placementopt/conductor/api_builder.py [moved from optimizers/placementopt/conductor/api_builder.py with 95% similarity]
osdf/optimizers/placementopt/conductor/conductor.py [moved from optimizers/placementopt/conductor/conductor.py with 100% similarity]
osdf/optimizers/placementopt/conductor/remote_opt_processor.py [moved from optimizers/placementopt/conductor/remote_opt_processor.py with 100% similarity]
osdf/optimizers/placementopt/conductor/translation.py [moved from optimizers/placementopt/conductor/translation.py with 98% similarity]
osdf/templates/cms_opt_request.jsont [new file with mode: 0755]
osdf/templates/cms_opt_request.jsont_1707_v1 [new file with mode: 0755]
osdf/templates/cms_opt_request_1702.jsont [new file with mode: 0755]
osdf/templates/cms_opt_response.jsont [new file with mode: 0644]
osdf/templates/conductor_interface.json [new file with mode: 0755]
osdf/templates/license_opt_request.jsont [new file with mode: 0644]
osdf/templates/plc_opt_request.jsont [new file with mode: 0755]
osdf/templates/plc_opt_response.jsont [new file with mode: 0755]
osdf/templates/policy_request.jsont [new file with mode: 0755]
osdf/templates/test_cms_nb_req_from_client.jsont [new file with mode: 0755]
osdf/templates/test_plc_nb_req_from_client.jsont [new file with mode: 0755]
osdf/utils/__init__.py [moved from webapp/__init__.py with 100% similarity]
osdf/utils/data_conversion.py [moved from utils/data_conversion.py with 100% similarity]
osdf/utils/data_types.py [moved from utils/data_types.py with 100% similarity]
osdf/utils/interfaces.py [moved from utils/interfaces.py with 100% similarity]
osdf/utils/local_processing.py [moved from utils/local_processing.py with 100% similarity]
osdf/utils/programming_utils.py [moved from utils/programming_utils.py with 100% similarity]
osdf/webapp/__init__.py [new file with mode: 0644]
osdf/webapp/appcontroller.py [moved from webapp/appcontroller.py with 100% similarity]
requirements.txt [new file with mode: 0644]
test/bad_test_Utils.py [new file with mode: 0644]
test/dummy_test_dummy.py [new file with mode: 0644]
test/placement-tests/request.json [new file with mode: 0644]
test/placement-tests/request_mso.json [new file with mode: 0644]
test/placement-tests/request_mso_subs_name_blank.json [new file with mode: 0644]
test/placement-tests/request_mso_subs_name_default.json [new file with mode: 0644]
test/placement-tests/request_mso_subs_name_none.json [new file with mode: 0644]
test/placement-tests/request_mso_subs_name_null.json [new file with mode: 0644]
test/placement-tests/request_vCPE.json [new file with mode: 0644]
test/placement-tests/scopePolicies.json [new file with mode: 0644]
test/placement-tests/testScoperequest.json [new file with mode: 0644]
test/placement-tests/test_by_scope.yaml [new file with mode: 0644]
test/placement-tests/vnfGroupPolicies.txt [new file with mode: 0644]
test/policy-local-files/CloudAttributePolicy_vGMuxInfra_1.json [new file with mode: 0644]
test/policy-local-files/CloudAttributePolicy_vG_1.json [new file with mode: 0644]
test/policy-local-files/DistanceToLocationPolicy_vGMuxInfra_1.json [new file with mode: 0644]
test/policy-local-files/DistanceToLocationPolicy_vG_1.json [new file with mode: 0644]
test/policy-local-files/InventoryGroup_vGMuxInfra_1.json [new file with mode: 0644]
test/policy-local-files/InventoryGroup_vG_1.json [new file with mode: 0644]
test/policy-local-files/PlacementOptimizationPolicy.json [new file with mode: 0644]
test/policy-local-files/ResourceInstancePolicy_vG_1.json [new file with mode: 0644]
test/policy-local-files/VNFPolicy_vGMuxInfra_1.json [new file with mode: 0644]
test/policy-local-files/VNFPolicy_vG_1.json [new file with mode: 0644]
test/policy-local-files/ZonePolicy_vGMuxInfra_1.json [new file with mode: 0644]
test/policy-local-files/ZonePolicy_vG_1.json [new file with mode: 0644]
test/test-requirements.txt [new file with mode: 0644]
test/test_ConductorApiBuilder.py [new file with mode: 0644]
test/test_PolicyCalls.py [new file with mode: 0644]
tox.ini [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..864f9ee
--- /dev/null
@@ -0,0 +1,110 @@
+# Copied from https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore
+# Copy as of 2018-02-08
+# github/gitignore is licensed under the
+# Creative Commons Zero v1.0 Universal
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+.static_storage/
+.media/
+local_settings.py
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..fffadb0
--- /dev/null
@@ -0,0 +1,26 @@
+
+The following licence applies to all files in this and subdirectories. Licences
+are included in individual source files where appropriate, and if it differs
+from this text, it supersedes this.  Any file that does not have licence text
+defaults to being covered by this text; not all files support the addition of
+licenses. 
+
+#
+# -------------------------------------------------------------------------
+#   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.
+#
+# -------------------------------------------------------------------------
+#
+
diff --git a/config/common_config.yaml b/config/common_config.yaml
new file mode 100644 (file)
index 0000000..d8f467b
--- /dev/null
@@ -0,0 +1,43 @@
+osdf_system:
+    libpath: /opt/app/osdf/libs
+    sniro_ports:
+        internal: 24699  # inside the Docker container, the app listens to this port
+        external: 14699  # clients use this port on DockerHost
+        # Important Note: At deployment time, we need to ensure the port mapping is done
+    ssl_context: ['./../etc/sniromanager.crt', './../etc/sniromanager.key']
+
+osdf_temp:  # hacks 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)
+            - CloudAttributePolicy_vGMuxInfra_1.json
+            - CloudAttributePolicy_vG_1.json
+            - DistanceToLocationPolicy_vGMuxInfra_1.json
+            - DistanceToLocationPolicy_vG_1.json
+            - InventoryGroup_vGMuxInfra_1.json
+            - InventoryGroup_vG_1.json
+            - PlacementOptimizationPolicy.json
+            - ResourceInstancePolicy_vG_1.json
+            - VNFPolicy_vGMuxInfra_1.json
+            - VNFPolicy_vG_1.json
+            - ZonePolicy_vGMuxInfra_1.json
+            - ZonePolicy_vG_1.json
+
+service_info:
+    vCPE:
+        vcpeHostName: requestParameters.vcpeHostName
+        e2eVpnKey: requestParameters.e2eVpnKey
+
+policy_info:
+    placement:
+        policy_fetch: by_scope
+        policy_scope:
+            default_scope: OSDF_R2
+            scope_vcpe: OSDF_R2
+            service_name: placementInfo.serviceModelInfo.modelName
+        policy_subscriber: SubscriberPolicy
+        subscriber_name: placementInfo.subscriberInfo.subscriberName
+    default:  # if no explicit service related information is needed
+        policy_fetch: by_name
+        policy_scope: none
diff --git a/config/osdf_config.yaml b/config/osdf_config.yaml
new file mode 100755 (executable)
index 0000000..69ebdf0
--- /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: "https://OOF-HAS-CONDUCTOR-HOST:8091"
+conductorUsername: "CONDUCTOR-USER"
+conductorPassword: "CONDUCTOR-PASSWD"
+conductorPingWaitTime: 60  # seconds to wait before calling the conductor retry URL
+conductorMaxRetries: 30  # if we don't get something in 30 minutes, give up
+
+# Policy Platform -- requires ClientAuth, Authorization, and Environment
+policyPlatformUrl: https://POLICY-URL:8081/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"
similarity index 100%
rename from __init__.py
rename to osdf/__init__.py
similarity index 97%
rename from adapters/policy/interface.py
rename to osdf/adapters/policy/interface.py
index ee45051..4ddee15 100644 (file)
@@ -29,7 +29,7 @@ from osdf.config.base import osdf_config
 from osdf.logging.osdf_logging import audit_log, MH, metrics_log, error_log, debug_log
 from osdf.utils.interfaces import RestClient
 from osdf.optimizers.placementopt.conductor.api_builder import retrieve_node
-from osdf.utils import data_mapping
+from osdf.utils import data_mapping
 
 
 def get_by_name(rest_client, policy_name_list, wildcards=True):
@@ -109,9 +109,10 @@ def get_by_scope(rest_client, req, config_local, type_service):
     pscope = pmain['policy_scope']
     
     model_name = retrieve_node(req, pscope['service_name'])
-    service_name = data_mapping.get_request_service_type(req)
-    if service_name is None:
-        service_name = data_mapping.get_service_type(model_name)
+    service_name = model_name
+    # service_name = data_mapping.get_request_service_type(req)
+    # if service_name is None:
+    #     service_name = data_mapping.get_service_type(model_name)
     scope = pscope['scope_{}'.format(service_name.lower())]
     subscriber_role, prov_status = get_subscriber_role(rest_client, req, pmain, service_name, scope)
     policy_type_list = pmain['policy_type_{}'.format(service_name.lower())]
similarity index 100%
rename from config/__init__.py
rename to osdf/config/__init__.py
similarity index 100%
rename from config/base.py
rename to osdf/config/base.py
similarity index 100%
rename from config/loader.py
rename to osdf/config/loader.py
diff --git a/osdf/logging/osdf_logging.py b/osdf/logging/osdf_logging.py
new file mode 100755 (executable)
index 0000000..9a6ff4e
--- /dev/null
@@ -0,0 +1,229 @@
+import logging
+import traceback
+import uuid
+
+import logging
+from logging.handlers import RotatingFileHandler
+from osdf.utils.programming_utils import MetaSingleton
+
+
+def log_handlers_pre_onap(config_file="config/pre_onap_logging_common_v1.config",
+                          service_name="OOF_OSDF"):
+    """
+    Convenience handlers for logging to different log files
+
+    :param config_file: configuration file (properties file) that specifies log location, rotation, etc.
+    :param service_name: name for this service
+    :return: dictionary of log objects: "error", "metrics", "audit", "debug"
+
+    We can use the returned values as follows:
+    X["error"].fatal("a FATAL message for the error log")
+    X["error"].error("an ERROR message for the error log")
+    X["error"].warn("a WARN message for the error log")
+    X["audit"].info("an INFO message for the audit log")
+    X["metrics"].info("an INFO message for the metrics log")
+    X["debug"].debug("a DEBUG message for the debug log")
+    """
+    # Keeping main_params as a place-holder for ONAP related logging needs
+    # main_params = dict(instanceUUID=uuid.uuid1(), serviceName=service_name, configFile=config_file)
+    return dict((x, logging.getLogger(x))   # keep **main_params as a placeholder for ONAP fields
+                for x in ["error", "metrics", "audit", "debug"])
+
+
+def format_exception(err, prefix=None):
+    """Format operation for use with ecomp logging
+    :param err: exception object
+    :param prefix: prefix string message
+    :return: formatted exception (via repr(traceback.format_tb(err.__traceback__))
+    """
+    exception_lines = traceback.format_exception(err.__class__, err, err.__traceback__)
+    exception_desc = "".join(exception_lines)
+    return exception_desc if not prefix else prefix + ": " + exception_desc
+
+
+class OOF_OSDFLogMessageHelper(metaclass=MetaSingleton):
+    """Provides loggers as a singleton (otherwise, we end up with duplicate messages).
+    Provides error_log, metric_log, audit_log, and debug_log (in that order)
+    Additionally can provide specific log handlers too
+    """
+    log_handlers = None
+    default_levels = ["error", "metrics", "audit", "debug"]
+
+    def _setup_handlers(self, log_version="pre_onap", config_file=None, service_name=None):
+        """return error_log, metrics_log, audit_log, debug_log"""
+        if self.log_handlers is None:
+            params = {}
+            params.update({"config_file": config_file} if config_file else {})
+            params.update({"service_name": service_name} if service_name else {})
+
+            if log_version == "pre_onap":
+                self.log_handlers = log_handlers_pre_onap(**params)
+
+    def get_handlers(self, levels=None, log_version="pre_onap", config_file=None, service_name=None):
+        """Return ONAP-compliant log handlers for different levels. Each "level" ends up in a different log file
+        with a prefix of that level.
+
+        For example: error_log, metrics_log, audit_log, debug_log in that order
+        :param levels: None or list of levels subset of self.default_levels (["error", "metrics", "audit", "debug"])
+        :param log_version: Currently only pre_onap is supported
+        :param config_file: Logging configuration file for ONAP compliant logging
+        :param service_name: Name of the service
+        :return: list of log_handlers in the order of levels requested.
+              if levels is None: we return handlers for self.default_levels
+              if levels is ["error", "audit"], we return log handlers for that.
+        """
+        self._setup_handlers(log_version="pre_onap", config_file=config_file, service_name=service_name)
+        wanted_levels = self.default_levels if levels is None else levels
+        return [self.log_handlers.get(x) for x in wanted_levels]
+
+
+class OOF_OSDFLogMessageFormatter(object):
+
+    @staticmethod
+    def accepted_valid_request(req_id, request):
+        return "Accepted valid request for ID: {} for endpoint: {}".format(
+            req_id, request.url)
+
+    @staticmethod
+    def invalid_request(req_id, err):
+        return "Invalid request for request ID: {}; cause: {}".format(
+            req_id, format_exception(err))
+
+    @staticmethod
+    def invalid_response(req_id, err):
+        return "Invalid response for request ID: {}; cause: {}".format(
+            req_id, format_exception(err))
+
+    @staticmethod
+    def malformed_request(request, err):
+        return "Malformed request for URL {}, from {}; cause: {}".format(
+            request.url, request.remote_address, format_exception(err))
+
+    @staticmethod
+    def malformed_response(response, client, err):
+        return "Malformed response {} for client {}; cause: {}".format(
+            response, client, format_exception(err))
+
+    @staticmethod
+    def need_policies(req_id):
+        return "Policies required but found no policies for request ID: {}".format(req_id)
+
+    @staticmethod
+    def policy_service_error(url, req_id, err):
+        return "Unable to call policy for {} for request ID: {}; cause: {}".format(
+            url, req_id, format_exception(err))
+
+    @staticmethod
+    def requesting_url(url, req_id):
+        return "Making a call to URL {} for request ID: {}".format(url, req_id)
+
+    @staticmethod
+    def requesting(service_name, req_id):
+        return "Making a call to service {} for request ID: {}".format(service_name, req_id)
+
+    @staticmethod
+    def error_requesting(service_name, req_id, err):
+        return "Error while requesting service {} for request ID: {}; cause: {}".format(
+            service_name, req_id, format_exception(err))
+
+    @staticmethod
+    def calling_back(req_id, callback_url):
+        return "Posting result to callback URL for request ID: {}; callback URL={}".format(
+            req_id, callback_url)
+
+    @staticmethod
+    def calling_back_with_body(req_id, callback_url, body):
+        return "Posting result to callback URL for request ID: {}; callback URL={} body={}".format(
+            req_id, callback_url, body)
+
+    @staticmethod
+    def error_calling_back(req_id, callback_url, err):
+        return "Error while posting result to callback URL {} for request ID: {}; cause: {}".format(
+            req_id, callback_url, format_exception(err))
+
+    @staticmethod
+    def received_request(url, remote_addr, json_body):
+        return "Received a call to {} from {} {}".format(url, remote_addr, json_body)
+
+    @staticmethod
+    def new_worker_thread(req_id, extra_msg=""):
+        res = "Initiating new worker thread for request ID: {}".format(req_id)
+        return res + extra_msg
+
+    @staticmethod
+    def inside_worker_thread(req_id, extra_msg=""):
+        res = "Inside worker thread for request ID: {}".format(req_id)
+        return res + extra_msg
+
+    @staticmethod
+    def processing(req_id, desc):
+        return "Processing request ID: {} -- {}".format(req_id, desc)
+
+    @staticmethod
+    def processed(req_id, desc):
+        return "Processed request ID: {} -- {}".format(req_id, desc)
+
+    @staticmethod
+    def error_while_processing(req_id, desc, err):
+        return "Error while processing request ID: {} -- {}; cause: {}".format(
+            req_id, desc, format_exception(err))
+
+    @staticmethod
+    def creating_local_env(req_id):
+        return "Creating local environment request ID: {}".format(
+            req_id)
+
+    @staticmethod
+    def error_local_env(req_id, desc, err):
+        return "Error while creating local environment for request ID: {} -- {}; cause: {}".format(
+            req_id, desc, err.__traceback__)
+
+    @staticmethod
+    def inside_new_thread(req_id, extra_msg=""):
+        res = "Spinning up a new thread for request ID: {}".format(req_id)
+        return res + " " + extra_msg
+
+    @staticmethod
+    def error_response_posting(req_id, desc, err):
+        return "Error while posting a response for a request ID: {} -- {}; cause: {}".format(
+            req_id, desc, err.__traceback__)
+
+    @staticmethod
+    def received_http_response(resp):
+        return "Received response [code: {}, headers: {}, data: {}]".format(
+            resp.status_code, resp.headers, resp.__dict__)
+
+    @staticmethod
+    def sending_response(req_id, desc):
+        return "Response is sent for request ID: {} -- {}".format(
+            req_id, desc)
+
+    @staticmethod
+    def listening_response(req_id, desc):
+        return "Response is sent for request ID: {} -- {}".format(
+            req_id, desc)
+
+    @staticmethod
+    def items_received(item_num, item_type, desc="Received"):
+        return "{} {} {}".format(desc, item_num, item_type)
+
+    @staticmethod
+    def items_sent(item_num, item_type, desc="Published"):
+        return "{} {} {}".format(desc, item_num, item_type)
+
+
+MH = OOF_OSDFLogMessageFormatter
+error_log, metrics_log, audit_log, debug_log = OOF_OSDFLogMessageHelper().get_handlers()
+
+def warn_audit_error(msg):
+    """Log the message to error_log.warn and audit_log.warn"""
+    log_message_multi(msg, audit_log.warn, error_log.warn)
+
+
+def log_message_multi(msg, *logger_methods):
+    """Log the msg to multiple loggers
+    :param msg: message to log
+    :param logger_methods: e.g. error_log.warn, audit_log.warn, etc.
+    """
+    for log_method in logger_methods:
+        log_method(msg)
@@ -18,7 +18,7 @@
 
 import copy
 import json
-from osdf.utils import data_mapping
+from osdf.utils import data_mapping
 from jinja2 import Template
 from osdf.utils.programming_utils import list_flatten, dot_notation
 import osdf.optimizers.placementopt.conductor.translation as tr
@@ -61,8 +61,10 @@ def conductor_api_builder(request_json, flat_policies: list, local_config, prov_
     reservation_groups = list_flatten(reservation_policies)
     req_info = request_json['requestInfo']
     model_name = request_json['placementInfo']['serviceModelInfo']['modelName']
-    service_type = data_mapping.get_service_type(model_name)
+    service_type = model_name
+    # service_type = data_mapping.get_service_type(model_name)
     service_info = local_config.get('service_info', {}).get(service_type, {})
+    order_info = {}
     if 'orderInfo' in request_json["placementInfo"]:
         order_info = json.loads(request_json["placementInfo"]["orderInfo"])
     request_type = req_info.get('requestType', None)
@@ -70,7 +72,7 @@ def conductor_api_builder(request_json, flat_policies: list, local_config, prov_
     if 'subscriberInfo' in request_json['placementInfo']: 
         subs_com_site_id = request_json['placementInfo']['subscriberInfo'].get('subscriberCommonSiteId', "")
     if service_type == 'vCPE':
-        data_mapping.normalize_user_params(order_info)
+        data_mapping.normalize_user_params(order_info)
         rendered_req = templ.render(
             requestType=request_type,
             chosenComplex=subs_com_site_id,
@@ -83,7 +85,7 @@ def conductor_api_builder(request_json, flat_policies: list, local_config, prov_
             serviceType=service_type,
             serviceInstance=request_json['placementInfo']['serviceInstanceId'],
             provStatus = prov_status,
-            chosenRegion=order_info['requestParameters']['lcpCloudRegionId'],
+            chosenRegion=order_info.get('requestParameters',{}).get('lcpCloudRegionId'),
             json=json)
     elif service_type == 'UNKNOWN':
         rendered_req = templ.render(
@@ -18,7 +18,7 @@
 
 import json
 from osdf.utils.data_conversion import text_to_symbol
-from osdf.utils import data_mapping
+from osdf.utils import data_mapping
 
 def gen_optimization_policy(vnf_list, optimization_policy):
     """Generate optimization policy details to pass to Conductor
@@ -183,7 +183,8 @@ def get_demand_properties(demand, policies):
                     if 'attributes' in x:
                         attributes = {}
                         for k,v in x['attributes'].items():
-                            key=data_mapping.convert(k)
+                            # key=data_mapping.convert(k)
+                            key = k
                             attributes[key] = v
                             if(key=="model-invariant-id"):
                                 attributes[key]=demand['resourceModelInfo']['modelInvariantId']
diff --git a/osdf/templates/cms_opt_request.jsont b/osdf/templates/cms_opt_request.jsont
new file mode 100755 (executable)
index 0000000..006562b
--- /dev/null
@@ -0,0 +1,35 @@
+{
+  "transaction_id": "{{ transaction_id }}",
+  "request_id": "{{ request_id }}",
+  "start_date" : "{{ start_time }}",
+  "end_date" : "{{ end_time }}",
+  "change_elements" : {{ json.dumps(change_elements) }},
+  "constraints" : [
+    {
+      "type" : "general_concurrency_limit",
+      "parameters": [{{ concurrency_limit }}]
+    },
+
+    {
+      "type" : "allowed_forbidden_periods",
+      "parameters" : {{ json.dumps(allowed_periods) }}
+    }
+
+    {% if spatial_conflicts is defined and spatial_conflicts|length > 0 %}
+    ,
+    {
+      "type" : "spatial_conflict",
+      "parameters": {{ json.dumps(spatial_conflicts) }}
+    }
+    {% endif %}
+
+
+    {% if critical_periods is defined and spatial_conflicts|length > 0 %}
+    ,
+    {
+      "type" : "critical_periods",
+      "parameters": {{ json.dumps(critical_periods) }}
+    }
+    {% endif %}
+  ]
+}
diff --git a/osdf/templates/cms_opt_request.jsont_1707_v1 b/osdf/templates/cms_opt_request.jsont_1707_v1
new file mode 100755 (executable)
index 0000000..75ecbe5
--- /dev/null
@@ -0,0 +1,67 @@
+{
+  "transaction_id": "{{ transaction_id }}",
+  "request_id": "{{ request_id }}",
+  "start_date" : "{{ start_time }}",
+  "end_date" : "{{ end_time }}",
+
+  "change_elements" : [
+  {% set comma = joiner(",") -%}
+  {% for element in all_upgrades -%} {{ comma() }}
+    {
+      "id" : "{{ element.id }}",
+      "failback_duration": {{ element.failback_duration }},
+      {% if element.group_id -%}
+        "group_id": "{{ element.group_id }}",
+      {% endif %}
+      {% if element.scheduled_on -%}
+        "scheduled_on": "{{ element.scheduled_on }}",
+      {% endif %}
+      "duration": {{ element.duration }}
+    }
+  {% endfor -%}
+  ],
+
+  "constraints" : [
+    {
+      "type" : "general_concurrency_limit",
+      "parameters": [{{ concurrency_limit }}]
+    },
+
+    {
+      "type" : "allowed_forbidden_periods",
+      "parameters" : [
+      {% set comma = joiner(",") -%}
+      {% for idx in all_pending -%} {{ comma() }}
+        { "id" : "{{ idx.id }}",
+          "allowed_periods": [ {{ allowed_periods }}]
+        }
+      {% endfor -%}
+      ]
+    },
+    {
+      "type" : "spatial_conflict",
+      "parameters": [
+      {% set comma = joiner(",") -%}
+      {% for pserver, vce_list in vce_pserver_mapping.items() -%} {{ comma() }}
+        {
+          "spatial_entity": "{{ pserver }}",
+          "affected_entities": {{ vce_list }}
+        }
+      {% endfor -%}
+      ]
+    },
+
+    {
+      "type" : "critical_periods",
+      "parameters": [
+      {% set comma = joiner(",") -%}
+      {% for element, conflict_period in conflict_interval.items() -%} {{ comma() }}
+        {
+          "id" : "{{ element }}",
+          "periods": [{{ conflict_period }}]
+        }
+      {% endfor -%}
+      ]
+    }
+  ]
+}
diff --git a/osdf/templates/cms_opt_request_1702.jsont b/osdf/templates/cms_opt_request_1702.jsont
new file mode 100755 (executable)
index 0000000..bcafa45
--- /dev/null
@@ -0,0 +1,63 @@
+{
+  "request_id": "{{ request_id }}",
+  "startdate" : "{{ start_time }}",
+  "enddate" : "{{ end_time }}",
+
+  "change_elements" : [
+{% set comma = joiner(",") -%}
+{% for element in all_upgrades -%} {{ comma() }} 
+    { "id" : "{{ element.id }}",
+    {% if element.scheduled -%} "scheduled_on": "{{ element.scheduled }}", {% endif -%}
+    "duration": {{ element.duration }}, {# duration in seconds #}
+    "failback_duration": {{ element.failback_duration }}, {# duration in seconds #}
+    "group_id": {{ element.group_id }}, {# duration in seconds #}
+    }{% endfor -%}
+  ],
+
+  "constraints" : [
+    {
+      "type" : "general_concurrency_limit",
+      "parameters" : [ {{ general_concurrency_limit }} ]
+    },
+
+    {
+      "type" : "allowed_forbidden_periods",
+      "parameters" : [
+{% set comma = joiner(",") -%}
+{% for idx in all_pending -%} {{ comma() }}
+        { "id" : "{{ idx.id }}",
+          "allowed_periods": [ {% set comma2 = joiner(",") -%}
+          {% for period in allowed_periods -%} {{ comma2() }} [{{ json.dumps(period[0]) }}, {{ json.dumps(period[1]) }}]
+          {% endfor -%} ] }{% endfor -%}
+      ]
+    }
+
+{% if p_v_conflict is defined and p_v_conflict|length > 0 %}
+    ,
+    {
+      "type" : "critical_periods",
+      "description" : "Simultaneous upgrades",
+      "parameters" : [
+{% set comma2 = joiner(",") -%}
+{% for element in p_v_conflict -%} {{ comma2() }}
+        {
+          "id" : "{{ element[0]  }}",
+          "periods" : [{{ json.dumps(element[0]) }}, {{ json.dumps(element[1]) }}]
+        }
+{% endfor -%}
+{% endif %}
+
+{% for pserver, vce_group in grouped_vces.items() -%} {{ comma() }}
+    ,
+    {
+          "id" : "{{ pserver  }}",
+          "name" : "VCE's on pserver {{ pserver }}",
+          "description": "Only some VCEs on a pserver can be upgraded at a time",
+          "max_num_upgrades" : {{ max_num_upgrades(vce_group) }},
+          "upgrades" : {{ json.dumps(vce_group) }}
+        }
+{% endfor -%}
+      ]
+    }
+  ]
+}
diff --git a/osdf/templates/cms_opt_response.jsont b/osdf/templates/cms_opt_response.jsont
new file mode 100644 (file)
index 0000000..a8817df
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "transactionId": "{{transaction_id}}",
+    "scheduleId":"{{schedule_id}}",
+    "requestState": "{{request_state}}",
+    "status": "{{status}}",
+    "description": "{{description}}",
+    "schedule": {{schedule}}
+}
\ No newline at end of file
diff --git a/osdf/templates/conductor_interface.json b/osdf/templates/conductor_interface.json
new file mode 100755 (executable)
index 0000000..2b48647
--- /dev/null
@@ -0,0 +1,81 @@
+{\r
+  "name": "{{ name }}",\r
+  "files": {},\r
+  "timeout": {{ timeout }},\r
+  "limit": {{ limit }},\r
+  "template": {\r
+    "conductor_template_version": "2018-02-01",\r
+    "parameters": {\r
+           "REQUEST_TYPE": "{{ requestType }}",\r
+        "CHOSEN_REGION": "{{ chosenRegion }}",\r
+        "LATITUDE": "{{ latitude }}",\r
+        "LONGITUDE": "{{ longitude }}",\r
+        {% if serviceType == 'DHV' %}\r
+        "E2EVPNKEY": "{{ e2eVpnKey }}",\r
+        "UCPEHOST": "{{ ucpeHostName }}",\r
+        "EFFECTIVE_BANDWIDTH": "{{ effectiveBandwidth }}",\r
+        "WAN_PORT1_UP": "{{ ipsec_bw_up }}",\r
+        "WAN_PORT1_DOWN": "{{ ipsec_bw_down }}",\r
+        "WAN_PORT2_UP": "{{ ipsec2_bw_up }}",\r
+        "WAN_PORT2_DOWN": "{{ ipsec2_bw_down }}",\r
+        {% endif %}\r
+        {% if serviceType != 'DHV' %}\r
+        "GW_TENANT_ID": "{{ gwTenantId }}",\r
+        "PORTAL_TENANT_ID": "{{ portalTenantId }}",\r
+        {% endif %}\r
+        "CHOSEN_COMPLEX": "{{ chosenComplex }}",\r
+        {% if serviceType == 'ADIOD' or serviceType == 'VPE' %}\r
+        "BANDWIDTH": "{{ bandwidth }}",\r
+        "UNIT": "{{ bandwidth_unit }}",\r
+        {% endif %}\r
+        "SERVICE_INST": "{{ serviceInstance }}",\r
+       "PROV_STATUS": {{ json.dumps(provStatus) }}\r
+    },\r
+    "locations": {\r
+        {% if serviceType == 'DHV' %}\r
+        "customer_loc": {\r
+            "host_name": { "get_param": "UCPEHOST" }\r
+        }\r
+        {% elif serviceType == 'ADIOD' %}\r
+        "customer_pref_location": {\r
+            "clli_code": { "get_param": "CHOSEN_COMPLEX" }\r
+        }\r
+        {% elif serviceType == 'NETBOND' %}\r
+        "peering_point": {\r
+            "latitude": { "get_param": "LATITUDE" },\r
+            "longitude": { "get_param": "LONGITUDE" }\r
+        }\r
+        {% else %}\r
+        "customer_pref_loc": {\r
+            "clli_code": { "get_param": "CHOSEN_COMPLEX" }\r
+        }\r
+        {% endif %}\r
+    },\r
+    "demands": {{ json.dumps(demand_list) }},\r
+    {% set comma_main = joiner(",") %}\r
+    "constraints": {\r
+      {% set comma=joiner(",") %}\r
+      {% for elem in policy_groups %} {{ comma() }}\r
+        {% for key, value in elem.items() %}\r
+          "{{key}}": {{ json.dumps(value) }}\r
+        {% endfor %}\r
+      {% endfor %}\r
+    },\r
+    "reservation": {\r
+      {% set comma=joiner(",") %}\r
+      {% for elem in reservation_groups %} {{ comma() }}\r
+        {% for key, value in elem.items() %}\r
+          "{{key}}": {{ json.dumps(value) }}\r
+        {% endfor %}\r
+      {% endfor %}\r
+    },\r
+    "optimization": {\r
+      {% set comma=joiner(",") %}\r
+      {% for elem in optimization_policies %} {{ comma() }}\r
+        {% for key, value in elem.items() %}\r
+          "{{key}}": {{ json.dumps(value) }}\r
+        {% endfor %}\r
+      {% endfor %}\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/osdf/templates/license_opt_request.jsont b/osdf/templates/license_opt_request.jsont
new file mode 100644 (file)
index 0000000..7baa759
--- /dev/null
@@ -0,0 +1,6 @@
+{
+       "transactionId": "{{transaction_id}}",
+       "requestId": "{{request_id}}",
+    "partNumber": "{{part_number}}",
+       "licenseModel" : "{{artifact}}"
+}
\ No newline at end of file
diff --git a/osdf/templates/plc_opt_request.jsont b/osdf/templates/plc_opt_request.jsont
new file mode 100755 (executable)
index 0000000..cd78b3e
--- /dev/null
@@ -0,0 +1,142 @@
+{\r
+  "name": "{{ name }}",\r
+  "files": "{{ files }}",\r
+  "timeout": "{{ timeout }}",\r
+  "limit": "{{ limit }}",\r
+  "template": {\r
+    "CUST_ID": "{{ cust_id }}",\r
+    "E2EVPNKEY": "{{ e2evpnkey }}",\r
+    "UCPEHOST": "{{ ucpehost }}",\r
+    "WAN_PORT1_UP": "{{ wan_port1_up }}",\r
+    "WAN_PORT1_DOWN": "{{ wan_port1_down }}",\r
+    "EFFECTIVE_BANDWIDTH": "{{ effective_bandwidth }}",\r
+    "SERVICE_INST": "{{ service_inst }}",\r
+    "locations": {\r
+      "customer_loc": {\r
+        "host_name": "{{ ucpehost }}"\r
+      }\r
+    },\r
+    "demands": [\r
+      {% set comma=joiner(",") %}\r
+      {% for demand in demand_list %} {{ comma() }}\r
+      {\r
+        "{{ demand.vnf_name }}": [\r
+          {% set comma2=joiner(",") %}\r
+          {% for property in demand.property %}\r
+            "inventory_provider": {{ property.inventory_provider }},\r
+            "inventory_type": {{ property.inventory_type }},\r
+            "service_type": {{ property.service_type }},\r
+            "customer_id": {{ property.customer_id }},\r
+            "candidate_id": {{ property.candidate_id }}\r
+          {% endfor %}\r
+        ]\r
+      }\r
+      {% endfor %}\r
+    ],\r
+    "constraints": {\r
+      {% set comma_main=joiner(",") %}\r
+\r
+      {% if attribute_policy_list %} {{ comma_main() }} {% endif %}\r
+      {% set comma=joiner(",") %}\r
+      {% for attribute in attribute_policy_list %} {{ comma() }}\r
+      attribute['identity'] : {\r
+        "type": {{ attribute['type'] }},\r
+        "demands": {{ attribute['demands'] }},\r
+        "properties": {\r
+          "evaluate": {\r
+            "hypervisor": {{ attribute['property']['hypervisor'] }},\r
+            "aic_version": {{ attribute['property']['aicVersion'] }},\r
+            "aic_type": {{ attribute['property']['aicType'] }},\r
+            "dataplane": {{ attribute['property']['datatype'] }},\r
+            "network_roles": {{ attribute['property']['networkRoles'] }},\r
+            "complex": {{ attribute['property']['complex'] }}\r
+          }\r
+        }\r
+      }\r
+      {% endfor %}\r
+\r
+      {% if distance_to_location_policy_list %} {{ comma_main() }} {% endif %}\r
+      {% set comma=joiner(",") %}\r
+      {% for distance_location in distance_to_location_policy_list %} {{ comma() }}\r
+      distance_location['identity'] : {\r
+        "type": {{ distance_location['type'] }},\r
+        "demands": {{ distance_location['demands'] }},\r
+        "properties": {\r
+          "distance": {{ distance_location['property']['distance'] }},\r
+          "location": {{ distance_location['property']['location'] }}\r
+        }\r
+      }\r
+      {% endfor %}\r
+\r
+      {% if inventory_policy_list %} {{ comma_main() }} {% endif %}\r
+      {% set comma=joiner(",") %}\r
+      {% for inventory in inventory_policy_list %} {{ comma() }}\r
+      inventory['identity'] : {\r
+        "type": {{ inventory['type'] }},\r
+        "demands": {{ inventory['demands'] }}\r
+      }\r
+      {% endfor %}\r
+\r
+      {% if resource_instance_policy_list %} {{ comma_main() }} {% endif %}\r
+      {% set comma=joiner(",") %}\r
+      {% for resource_instance in resource_instance_policy_list %} {{ comma() }}\r
+      resource_instance['identity'] : {\r
+        "type": {{ resource_instance['type'] }},\r
+        "demands": {{ resource_instance['demands'] }},\r
+        "properties": {\r
+          "controller": {{ resource_instance['property']['controller'] }},\r
+          "request": {{ resource_instance['property']['request'] }}\r
+        }\r
+      }\r
+      {% endfor %}\r
+\r
+      {% if resource_region_policy_list %} {{ comma_main() }} {% endif %}\r
+      {% set comma=joiner(",") %}\r
+      {% for resource_region in resource_region_policy_list %} {{ comma() }}\r
+      resource_region['identity'] : {\r
+        "type": {{ resource_region['type'] }},\r
+        "demands": {{ resource_region['demands'] }},\r
+        "properties": {\r
+          "controller": {{ resource_region['property']['controller'] }},\r
+          "request": {{ resource_region['property']['request'] }}\r
+        }\r
+      }\r
+      {% endfor %}\r
+\r
+      {% if zone_policy_list %} {{ comma_main() }} {% endif %}\r
+      {% set comma=joiner(",") %}\r
+      {% for zone in zone_policy_list %} {{ comma() }}\r
+      zone['identity'] : {\r
+        "type": {{ zone['type'] }},\r
+        "demands": {{ zone['demands'] }},\r
+        "properties": {\r
+          "qualifier": {{ resource_region['property']['qualifier'] }},\r
+          "category": {{ resource_region['property']['category'] }}\r
+        }\r
+      }\r
+      {% endfor %}\r
+\r
+      {%  if optmization_policy_list %} {{ comma_main() }} {% endif %}\r
+      {% set comma=joiner(",") %}\r
+      {% for optimization in optimization_policy_list %} {{ comma() }}\r
+      "optimization" : {\r
+        {{ optimization['objective'] }}: {\r
+          "sum": [\r
+            {% set comma2=joiner(",") %}\r
+            {% for parameter in optimization['parameter'] %} {{ comma() }}\r
+            {\r
+              "product": [\r
+                {{ parameter['weight'] }},\r
+                {\r
+                  "distance_between": [{{ parameter['customerLocation'] }},{{ parameter['demand'] }}]\r
+                }\r
+              ]\r
+            }\r
+            {% endfor %}\r
+          ]\r
+        }\r
+      }\r
+      {% endfor %}\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/osdf/templates/plc_opt_response.jsont b/osdf/templates/plc_opt_response.jsont
new file mode 100755 (executable)
index 0000000..aa678b5
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "requestId": "{{requestId}}",
+  "transactionId": "{{transacationId}}",
+  "startTime": "{{startTime}}",
+  "responseTime": "{{responseTime}}",
+  "requestType": "{{requestType}}",
+  "requestState": "{{requestState}}",
+  "statusMessage": "{{statusMessage}}",
+  "percentProgress": "{{percentProgress}}",
+  "solutionInfo": {
+      "placement": {{ json.dumps(composite_solutions) }},
+      "licenseInfo":{ "featureGroupId": "{{featureGroupId}}" }
+  }
+}
diff --git a/osdf/templates/policy_request.jsont b/osdf/templates/policy_request.jsont
new file mode 100755 (executable)
index 0000000..3a9e201
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "policyName": "{{policy_name}}"  {# we currently only support query by policy name only -- policyName #}
+}
diff --git a/osdf/templates/test_cms_nb_req_from_client.jsont b/osdf/templates/test_cms_nb_req_from_client.jsont
new file mode 100755 (executable)
index 0000000..a60c8ff
--- /dev/null
@@ -0,0 +1,19 @@
+{
+       "schedulingInfo": { 
+        "change_management_id": "{{ change_management_id }}",
+        "start_time": "{{ start_time }}",
+        "end_time": "{{ end_time }}",
+        "policy_id": {{ json.dumps(policy_id) }},  {# a list of policy Ids #}
+        "service_type": "{{ service_type }}",
+        "workflow_type": "{{ workflow_type }}",
+        "upgrades": {{ json.dumps(upgrades) }}   {# a list of node Ids #}
+    }, 
+    "requestInfo": {
+        "requestId": "{{ requestId }}",
+        "sourceId": "{{ sourceId }}",
+        "optimizer": "{{ optimizer }}",
+        "numSolutions": "{{ numSolutions }}",
+        "callbackUrl" : "{{ callbackUrl }}"
+    }
+}
+
diff --git a/osdf/templates/test_plc_nb_req_from_client.jsont b/osdf/templates/test_plc_nb_req_from_client.jsont
new file mode 100755 (executable)
index 0000000..998ffb3
--- /dev/null
@@ -0,0 +1,52 @@
+{\r
+  "requestInfo": {\r
+        "requestId": "{{requestId}}",\r
+        "sourceId": "{{sourceId}}",\r
+        "optimizer": "{{optimizer}}",\r
+        "numSolutions": {{numSolutions}},\r
+        "timeout": {{timeout}},\r
+        "callbackUrl" : "{{callbackUrl}}"\r
+  },\r
+  "placementInfo": {\r
+      "modelInfo": {\r
+          "modelType": "{{modelType}}",\r
+          "modelInvariant": "{{modelInvariantId}}",\r
+          "modelVersionId": "{{modelVersionId}}",\r
+          "modelName": "{{modelName}}",\r
+          "modelVersion": "{{modelVersion}}",\r
+          "modelCustomizationId": "{{modelCustomizationId}}"\r
+      },\r
+      "subscriberInfo": {\r
+          "globalSubscriberId": "{{globalSubscriberId}}",\r
+          "subscriberName": "{{subscriberName}}",\r
+          "subscriberCommonSiteId": "{{subscriberCommonSiteId}}",\r
+          "ucpeHostName": "{{ucpeHostName}}"\r
+      },\r
+      "policyId": {{json.dumps(policyId)}},\r
+      "vnfInfo": {\r
+        "vnfType": "{{vnfType}}",\r
+        "vnfPartNumber": "{{vnfPartNumber}}",\r
+        "nominalThroughput": "{{nominalThroughput}}",\r
+        "vnfSoftwareVersion": "{{vnfSoftwareVersion}}",\r
+        "vnfManagementOption": "{{vnfManagementOption}}"\r
+      },\r
+      "vpnInfo": {\r
+        "vpnId": "{{vpnId}}",\r
+        "pvcId":  "{{pvcId}}"\r
+      },\r
+      "serviceInfo": {\r
+        "dhvServiceInfo": {\r
+          "serviceInstanceId": "{{serviceInstanceId}}",\r
+          "serviceType": "{{serviceType}}",\r
+          "e2evpnkey": "{{e2evpnkey}}",\r
+          "dhvSiteEffectiveTransportBandwidth": {{dhvSiteEffectiveTransportBandwidth}},\r
+          "dhvIPSecTransportBandwidthUp": {{dhvIPSecTransportBandwidthUp}},\r
+          "dhvIPSecTransportBandwidthDown": {{dhvIPSecTransportBandwidthDown}},\r
+          "dhvIPSec2TransportBandwidthUp": {{dhvIPSec2TransportBandwidthUp}},\r
+          "dhvIPSec2TransportBandwidthDown": {{dhvIPSec2TransportBandwidthDown}},\r
+          "dhvVendorName": "{{dhvVendorName}}"\r
+        }\r
+      },\r
+      "demandInfo": {{json.dumps(demandInfo)}}\r
+  }\r
+}\r
similarity index 100%
rename from webapp/__init__.py
rename to osdf/utils/__init__.py
similarity index 100%
rename from utils/data_types.py
rename to osdf/utils/data_types.py
similarity index 100%
rename from utils/interfaces.py
rename to osdf/utils/interfaces.py
diff --git a/osdf/webapp/__init__.py b/osdf/webapp/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..351f97e
--- /dev/null
@@ -0,0 +1,13 @@
+docutils>=0.12
+docopt>=0.6.2
+Flask>=0.11.1
+Flask-HTTPAuth>=3.2.2
+jsonschema>=2.5.1
+lxml>=3.6.4
+nose>=1.3.7
+python-dateutil>=2.5.3
+PyYAML>=3.12
+requests>=2.14.2
+schematics>=2.0.0
+docopt>=0.6.2
+pydevd>=1.0.0
diff --git a/test/bad_test_Utils.py b/test/bad_test_Utils.py
new file mode 100644 (file)
index 0000000..3e5cecd
--- /dev/null
@@ -0,0 +1,21 @@
+import unittest
+import json
+
+from osdf.config.base import osdf_config
+from osdf.utils.programming_utils import dot_notation
+
+
+class TestUtils(unittest.TestCase):
+
+    def test_metrics(self):
+        with open('test/placement-tests/request.json', 'r') as f:
+            data = json.load(f)
+            placementInfo = data["placementInfo"]
+            config_local = osdf_config.core
+            self.assertEqual("USOSTCDALTX0101UJZZ11", dot_notation(placementInfo, config_local['service_info']['vCPE']['vcpeHostName']))
+            self.assertEqual("200", dot_notation(placementInfo, config_local['service_info']['vCPE']['e2eVpnKey']))
+            self.assertEqual(['vGMuxInfra', 'vG'], dot_notation(placementInfo, 'demandInfo.placementDemand.resourceModuleName'))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test/dummy_test_dummy.py b/test/dummy_test_dummy.py
new file mode 100644 (file)
index 0000000..dc46d50
--- /dev/null
@@ -0,0 +1,14 @@
+import osdf
+# import osdfapp
+from osdf.config.loader import load_config_file
+
+
+def test_dummy():
+    """Generate time constraints from cm-request.json and cm-policy-response.json"""
+    try:
+       load_config_file("DUMMY")
+    except:
+       pass
+    return 1
+
+
diff --git a/test/placement-tests/request.json b/test/placement-tests/request.json
new file mode 100644 (file)
index 0000000..2fd425c
--- /dev/null
@@ -0,0 +1,87 @@
+{\r
+       "requestInfo": {\r
+               "transactionId": "xxx-xxx-xxxx",\r
+               "requestId": "yyy-yyy-yyyy",\r
+               "callbackUrl": "https://test.url.com:5000/callback/",\r
+               "sourceId": "so",\r
+               "optimizers": ["placement"],\r
+               "numSolutions": 1,\r
+               "timeout": 600\r
+       },\r
+       "placementInfo": {\r
+               "serviceModelInfo": {\r
+                       "modelType": "service",\r
+                       "modelInvariantId": "fad5f4d5-1c94-4890-927d-9cec6e82997f",\r
+                       "modelVersionId": "6e13c5e1-f172-436c-9cc4-0d64c94eb7f4",\r
+                       "modelName": "vCPE",\r
+                       "modelVersion": "1.0"\r
+               },\r
+               "subscriberInfo": {\r
+                       "globalSubscriberId": "SUB12_0325_UD_0833",\r
+                       "subscriberName": "SUB_12_0325_UD_0833",\r
+                       "subscriberCommonSiteId": "DALTX0101"\r
+               },\r
+               "demandInfo": {\r
+                       "placementDemand": [{\r
+                                       "resourceInstanceType": "allotted",\r
+                                       "serviceResourceId": "61d563e8-e714-4393-8f99-cc480144a05e",\r
+                                       "resourceModuleName": "vGMuxInfra",\r
+                                       "exclusionCandidateInfo": [{\r
+                                                       "candidateType": "cloud",\r
+                                                       "candidates": ["MDT54NJ", "BDM78NJ"]\r
+                                               }, {\r
+                                                       "candidateType": "service",\r
+                                                       "candidates": ["RT76U8F789", "PO098HJG"]\r
+                                               }\r
+                                       ],\r
+                                       "requiredCandidateInfo": [{\r
+                                                       "candidateType": "cloud",\r
+                                                       "candidates": ["DHU87NY"]\r
+                                               }, {\r
+                                                       "candidateType": "service",\r
+                                                       "candidates": ["YHT675YH"]\r
+                                               }\r
+                                       ],\r
+                                       "resourceModelInfo": {\r
+                                               "modelCustomizationId": "",\r
+                                               "modelInvariantId": "h59988ce-3d81-4e07-81b5-53d3aa821134",\r
+                                               "modelName": "",\r
+                                               "modelVersion": "2.0",\r
+                                               "modelVersionId": "51d563e8-e714-4393-8f99-cc480144a05e",\r
+                                               "modelType": "allotted"\r
+                                       },\r
+                                       "tenantId": "",\r
+                                       "tenantName": ""\r
+                               }, {\r
+                                       "resourceInstanceType": "allotted",\r
+                                       "serviceResourceId": "71d563e8-e714-4393-8f99-cc480144a05e",\r
+                                       "resourceModuleName": "vG",\r
+                                       "resourceModelInfo": {\r
+                                               "modelCustomizationId": "",\r
+                                               "modelInvariantId": "a59988ce-3d81-4e07-81b5-53d3aa821134",\r
+                                               "modelName": "",\r
+                                               "modelVersion": "2.0",\r
+                                               "modelVersionId": "91d563e8-e714-4393-8f99-cc480144a05e",\r
+                                               "modelType": "allotted"\r
+                                       },\r
+                                       "tenantId": "",\r
+                                       "tenantName": ""\r
+                               }\r
+                       ],\r
+                       "licenseDemand": []\r
+               },\r
+               "policyId": [\r
+                       ""\r
+               ],\r
+               "serviceInstanceId": "1234-fsdf-23sdf-24kjnk",\r
+               "requestParameters": {\r
+\r
+                               "commonSiteId": "DALTX0101",\r
+                               "vendorName": "xyz",\r
+                               "e2eVpnKey": "200",\r
+                               "vcpeHostName": "USOSTCDALTX0101UJZZ11"\r
+\r
+               }\r
+\r
+       }\r
+}
\ No newline at end of file
diff --git a/test/placement-tests/request_mso.json b/test/placement-tests/request_mso.json
new file mode 100644 (file)
index 0000000..2d854cb
--- /dev/null
@@ -0,0 +1,63 @@
+{
+       "requestInfo": {
+               "transactionId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "requestId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "callbackUrl": "http://127.0.0.1:7001",
+               "sourceId": "mso",
+               "optimizer": [
+                       "placement",
+                       "license"
+               ],
+               "numSolutions": 1,
+               "timeout": 600
+       },
+       "placementInfo": {
+               "serviceModelInfo": {
+                       "modelType": "",
+                       "modelInvariantId": "598e3f9e-3244-4d8f-a8e0-0e5d7a29eda9",
+                       "modelVersionId": "b8c45108-68df-48c5-8d58-c8dd4de833bb",
+                       "modelName": "ADIOD vMX vPE_BV Service 488",
+                       "modelVersion": "1.0"
+               },
+               "subscriberInfo": {
+                       "globalSubscriberId": "21014aa2-526b-11e6-beb8-9e71128cae77",
+                       "subscriberName": "Avteet_Chayal",
+                       "subscriberCommonSiteId": "MDTWNJ2B17"
+               },
+               "demandInfo": {
+                       "placementDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       },
+                                       "tenantId": "",
+                                       "tenantName": ""
+                               }
+                       ],
+                       "licenseDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       }
+                               }
+                       ]
+               },
+               "policyId": [],
+               "serviceInstanceId": "28014cbe-b334-4d5c-839d-980157929b0b",
+               "orderInfo": "{\"requestParameters\": {\"aLaCarte\":false,\"usePreload\":true,\"subscriptionServiceType\":\"VPE\",\"alaCarteSet\":true,\"rebuildVolumeGroups\":false,\"userParams\":[{\"name\":\"2017488_adiodvpe0_vnf_config_template_version\",\"value\":\"17.2\"},{\"name\":\"2017488_adiodvpe0_bandwidth_units\",\"value\":\"Gbps\"},{\"name\":\"2017488_adiodvpe0_bandwidth\",\"value\":\"10\"},{\"name\":\"2017488_adiodvpe0_AIC_CLLI\",\"value\":\"MDTWNJ2B17\"},{\"name\":\"2017488_adiodvpe0_vnf_instance_name\",\"value\":\"mtnj309me6\"}],\"autoBuildVfModules\":false,\"cascadeDelete\":false}}"
+       }
+}
diff --git a/test/placement-tests/request_mso_subs_name_blank.json b/test/placement-tests/request_mso_subs_name_blank.json
new file mode 100644 (file)
index 0000000..3195786
--- /dev/null
@@ -0,0 +1,63 @@
+{
+       "requestInfo": {
+               "transactionId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "requestId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "callbackUrl": "http://127.0.0.1:7001",
+               "sourceId": "mso",
+               "optimizer": [
+                       "placement",
+                       "license"
+               ],
+               "numSolutions": 1,
+               "timeout": 600
+       },
+       "placementInfo": {
+               "serviceModelInfo": {
+                       "modelType": "",
+                       "modelInvariantId": "598e3f9e-3244-4d8f-a8e0-0e5d7a29eda9",
+                       "modelVersionId": "b8c45108-68df-48c5-8d58-c8dd4de833bb",
+                       "modelName": "ADIOD vMX vPE_BV Service 488",
+                       "modelVersion": "1.0"
+               },
+               "subscriberInfo": {
+                       "globalSubscriberId": "21014aa2-526b-11e6-beb8-9e71128cae77",
+                       "subscriberName": "",
+                       "subscriberCommonSiteId": "MDTWNJ2B17"
+               },
+               "demandInfo": {
+                       "placementDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       },
+                                       "tenantId": "",
+                                       "tenantName": ""
+                               }
+                       ],
+                       "licenseDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       }
+                               }
+                       ]
+               },
+               "policyId": [],
+               "serviceInstanceId": "28014cbe-b334-4d5c-839d-980157929b0b",
+               "orderInfo": "{\"requestParameters\": {\"aLaCarte\":false,\"usePreload\":true,\"subscriptionServiceType\":\"VPE\",\"alaCarteSet\":true,\"rebuildVolumeGroups\":false,\"userParams\":[{\"name\":\"2017488_adiodvpe0_vnf_config_template_version\",\"value\":\"17.2\"},{\"name\":\"2017488_adiodvpe0_bandwidth_units\",\"value\":\"Gbps\"},{\"name\":\"2017488_adiodvpe0_bandwidth\",\"value\":\"10\"},{\"name\":\"2017488_adiodvpe0_AIC_CLLI\",\"value\":\"MDTWNJ2B17\"},{\"name\":\"2017488_adiodvpe0_vnf_instance_name\",\"value\":\"mtnj309me6\"}],\"autoBuildVfModules\":false,\"cascadeDelete\":false}}"
+       }
+}
diff --git a/test/placement-tests/request_mso_subs_name_default.json b/test/placement-tests/request_mso_subs_name_default.json
new file mode 100644 (file)
index 0000000..86e2f82
--- /dev/null
@@ -0,0 +1,63 @@
+{
+       "requestInfo": {
+               "transactionId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "requestId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "callbackUrl": "http://127.0.0.1:7001",
+               "sourceId": "mso",
+               "optimizer": [
+                       "placement",
+                       "license"
+               ],
+               "numSolutions": 1,
+               "timeout": 600
+       },
+       "placementInfo": {
+               "serviceModelInfo": {
+                       "modelType": "",
+                       "modelInvariantId": "598e3f9e-3244-4d8f-a8e0-0e5d7a29eda9",
+                       "modelVersionId": "b8c45108-68df-48c5-8d58-c8dd4de833bb",
+                       "modelName": "ADIOD vMX vPE_BV Service 488",
+                       "modelVersion": "1.0"
+               },
+               "subscriberInfo": {
+                       "globalSubscriberId": "21014aa2-526b-11e6-beb8-9e71128cae77",
+                       "subscriberName": "default",
+                       "subscriberCommonSiteId": "MDTWNJ2B17"
+               },
+               "demandInfo": {
+                       "placementDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       },
+                                       "tenantId": "",
+                                       "tenantName": ""
+                               }
+                       ],
+                       "licenseDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       }
+                               }
+                       ]
+               },
+               "policyId": [],
+               "serviceInstanceId": "28014cbe-b334-4d5c-839d-980157929b0b",
+               "orderInfo": "{\"requestParameters\": {\"aLaCarte\":false,\"usePreload\":true,\"subscriptionServiceType\":\"VPE\",\"alaCarteSet\":true,\"rebuildVolumeGroups\":false,\"userParams\":[{\"name\":\"2017488_adiodvpe0_vnf_config_template_version\",\"value\":\"17.2\"},{\"name\":\"2017488_adiodvpe0_bandwidth_units\",\"value\":\"Gbps\"},{\"name\":\"2017488_adiodvpe0_bandwidth\",\"value\":\"10\"},{\"name\":\"2017488_adiodvpe0_AIC_CLLI\",\"value\":\"MDTWNJ2B17\"},{\"name\":\"2017488_adiodvpe0_vnf_instance_name\",\"value\":\"mtnj309me6\"}],\"autoBuildVfModules\":false,\"cascadeDelete\":false}}"
+       }
+}
diff --git a/test/placement-tests/request_mso_subs_name_none.json b/test/placement-tests/request_mso_subs_name_none.json
new file mode 100644 (file)
index 0000000..214e011
--- /dev/null
@@ -0,0 +1,62 @@
+{
+       "requestInfo": {
+               "transactionId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "requestId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "callbackUrl": "http://127.0.0.1:7001",
+               "sourceId": "mso",
+               "optimizer": [
+                       "placement",
+                       "license"
+               ],
+               "numSolutions": 1,
+               "timeout": 600
+       },
+       "placementInfo": {
+               "serviceModelInfo": {
+                       "modelType": "",
+                       "modelInvariantId": "598e3f9e-3244-4d8f-a8e0-0e5d7a29eda9",
+                       "modelVersionId": "b8c45108-68df-48c5-8d58-c8dd4de833bb",
+                       "modelName": "ADIOD vMX vPE_BV Service 488",
+                       "modelVersion": "1.0"
+               },
+               "subscriberInfo": {
+                       "globalSubscriberId": "21014aa2-526b-11e6-beb8-9e71128cae77",
+                       "subscriberCommonSiteId": "MDTWNJ2B17"
+               },
+               "demandInfo": {
+                       "placementDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       },
+                                       "tenantId": "",
+                                       "tenantName": ""
+                               }
+                       ],
+                       "licenseDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       }
+                               }
+                       ]
+               },
+               "policyId": [],
+               "serviceInstanceId": "28014cbe-b334-4d5c-839d-980157929b0b",
+               "orderInfo": "{\"requestParameters\": {\"aLaCarte\":false,\"usePreload\":true,\"subscriptionServiceType\":\"VPE\",\"alaCarteSet\":true,\"rebuildVolumeGroups\":false,\"userParams\":[{\"name\":\"2017488_adiodvpe0_vnf_config_template_version\",\"value\":\"17.2\"},{\"name\":\"2017488_adiodvpe0_bandwidth_units\",\"value\":\"Gbps\"},{\"name\":\"2017488_adiodvpe0_bandwidth\",\"value\":\"10\"},{\"name\":\"2017488_adiodvpe0_AIC_CLLI\",\"value\":\"MDTWNJ2B17\"},{\"name\":\"2017488_adiodvpe0_vnf_instance_name\",\"value\":\"mtnj309me6\"}],\"autoBuildVfModules\":false,\"cascadeDelete\":false}}"
+       }
+}
diff --git a/test/placement-tests/request_mso_subs_name_null.json b/test/placement-tests/request_mso_subs_name_null.json
new file mode 100644 (file)
index 0000000..df7ae8f
--- /dev/null
@@ -0,0 +1,63 @@
+{
+       "requestInfo": {
+               "transactionId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "requestId": "1b98ee53-3fbd-48ca-9b85-302792bf5918",
+               "callbackUrl": "http://127.0.0.1:7001",
+               "sourceId": "mso",
+               "optimizer": [
+                       "placement",
+                       "license"
+               ],
+               "numSolutions": 1,
+               "timeout": 600
+       },
+       "placementInfo": {
+               "serviceModelInfo": {
+                       "modelType": "",
+                       "modelInvariantId": "598e3f9e-3244-4d8f-a8e0-0e5d7a29eda9",
+                       "modelVersionId": "b8c45108-68df-48c5-8d58-c8dd4de833bb",
+                       "modelName": "ADIOD vMX vPE_BV Service 488",
+                       "modelVersion": "1.0"
+               },
+               "subscriberInfo": {
+                       "globalSubscriberId": "21014aa2-526b-11e6-beb8-9e71128cae77",
+                       "subscriberName": "null",
+                       "subscriberCommonSiteId": "MDTWNJ2B17"
+               },
+               "demandInfo": {
+                       "placementDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       },
+                                       "tenantId": "",
+                                       "tenantName": ""
+                               }
+                       ],
+                       "licenseDemand": [{
+                                       "resourceInstanceType": "VNF",
+                                       "serviceResourceId": "6ea4128a-ba41-4872-a1f8-2748d0e1c361",
+                                       "resourceModuleName": "2017-488_ADIOD-vPE 0",
+                                       "resourceModelInfo": {
+                                               "modelCustomizationId": "06ed941b-1d83-4132-8a1d-1874f4f4b89b",
+                                               "modelInvariantId": "5be7e99e-8eb2-4d97-be63-8081ff3cd10e",
+                                               "modelName": "2017-488_ADIOD-vPE",
+                                               "modelVersion": "1.0",
+                                               "modelVersionId": "7cd2d399-2bcb-4ecf-bd32-c36cdca7aa03",
+                                               "modelType": ""
+                                       }
+                               }
+                       ]
+               },
+               "policyId": [],
+               "serviceInstanceId": "28014cbe-b334-4d5c-839d-980157929b0b",
+               "orderInfo": "{\"requestParameters\": {\"aLaCarte\":false,\"usePreload\":true,\"subscriptionServiceType\":\"VPE\",\"alaCarteSet\":true,\"rebuildVolumeGroups\":false,\"userParams\":[{\"name\":\"2017488_adiodvpe0_vnf_config_template_version\",\"value\":\"17.2\"},{\"name\":\"2017488_adiodvpe0_bandwidth_units\",\"value\":\"Gbps\"},{\"name\":\"2017488_adiodvpe0_bandwidth\",\"value\":\"10\"},{\"name\":\"2017488_adiodvpe0_AIC_CLLI\",\"value\":\"MDTWNJ2B17\"},{\"name\":\"2017488_adiodvpe0_vnf_instance_name\",\"value\":\"mtnj309me6\"}],\"autoBuildVfModules\":false,\"cascadeDelete\":false}}"
+       }
+}
diff --git a/test/placement-tests/request_vCPE.json b/test/placement-tests/request_vCPE.json
new file mode 100644 (file)
index 0000000..03e32d9
--- /dev/null
@@ -0,0 +1,105 @@
+{
+  "requestInfo": {
+    "transactionId": "xxx-xxx-xxxx",
+    "requestId": "yyy-yyy-yyyy",
+    "callbackUrl": "https://so:5000/callbackUrl",
+    "sourceId": "SO",
+    "requestType": "create",
+    "numSolutions": 1,
+    "optimizers": ["placement"],
+    "timeout": 600
+  },
+  "requestParameters": {
+    "customerLatitude": 32.897480,
+    "customerLongitude": -97.040443,
+    "customerName": "xyz"
+  },
+  "placementDemands": [
+    {
+      "resourceModuleName": "vGMuxInfra",
+      "serviceResourceId": "vGMuxInfra-xx",
+      "tenantId": "vGMuxInfra-tenant",
+      "resourceModelInfo": {
+        "modelInvariantId": "vGMuxInfra-modelInvariantId",
+        "modelVersionId": "vGMuxInfra-versionId",
+        "modelName": "vGMuxInfra-model",
+        "modelType": "resource",
+        "modelVersion": "1.0",
+        "modelCustomizationName": "vGMuxInfra-customeModelName"
+      },
+      "existingCandidates": {
+        "identifierType": "service_instance_id",
+        "identifiers": ["87257b49-9602-4ca1-9817-094e52bc873b"]
+      },
+      "excludedCandidates": {
+        "identifierType": "service_instance_id",
+        "identifiers": ["1ac71fb8-ad43-4e16-9459-c3f372b8236d"]
+      },
+      "requiredCandidates": {
+        "identifierType": "service_instance_id",
+        "identifiers": ["7e6c3e57-62cd-44f6-aa88-d0896998f7ec"]
+      }
+    },
+    {
+      "resourceModuleName": "vG",
+      "serviceResourceId": "71d563e8-e714-4393-8f99-cc480144a05e",
+      "tenantId": "vG-tenant",
+      "resourceModelInfo": {
+        "modelInvariantId": "vG-modelInvariantId",
+        "modelVersionId": "vG-versionId",
+        "modelName": "vG-model",
+        "modelType": "resource",
+        "modelVersion": "1.0",
+        "modelCustomizationName": "vG-customeModelName"
+      },
+      "existingCandidates": {
+        "identifierType": "service_instance_id",
+        "identifiers": ["21d5f3e8-e714-4383-8f99-cc480144505a"]
+      },
+      "excludedCandidates": {
+        "identifierType": "service_instance_id",
+        "identifiers": ["1ac71fb8-ad43-4e16-9459-c3f372b8236d"]
+      },
+      "requiredCandidates": {
+        "identifierType": "cloud_region_id",
+        "identifiers": ["TXAUS219"]
+      }
+    }
+  ],
+  "serviceInfo": {
+    "serviceInstanceId": "d61b2543-5914-4b8f-8e81-81e38575b8ec",
+    "serviceModelInfo": {
+      "modelInvariantId": "vCPE-invariantId",
+      "modelVersionId": "vCPE-versionId",
+      "modelName": "vCPE-model",
+      "modelType": "service",
+      "modelVersion": "1.0",
+      "modelCustomizationName": "vCPE-customeModelName"
+    }
+  },
+  "licenseDemands": [
+    {
+      "resourceModuleName": "vGMuxInfra",
+      "serviceResourceId": "vGMuxInfra-xx",
+      "tenantId": "vGMuxInfra-tenant",
+      "resourceModelInfo": {
+        "modelInvariantId": "vGMuxInfra-modelInvariantId",
+        "modelVersionId": "vGMuxInfra-versionId",
+        "modelName": "vGMuxInfra-model",
+        "modelType": "resource",
+        "modelVersion": "1.0",
+        "modelCustomizationName": "vGMuxInfra-customeModelName"
+      },
+      "existingLicenses": {
+        "entitlementPoolUUID": [
+          "87257b49-9602-4ca1-9817-094e52bc873b",
+          "43257b49-9602-4fe5-9337-094e52bc9435"
+        ],
+        "licenseKeyGroupUUID": [
+          "87257b49-9602-4ca1-9817-094e52bc873b",
+          "43257b49-9602-4fe5-9337-094e52bc9435"
+        ]
+      }
+    }
+  ]
+}
diff --git a/test/placement-tests/scopePolicies.json b/test/placement-tests/scopePolicies.json
new file mode 100644 (file)
index 0000000..123c8e2
--- /dev/null
@@ -0,0 +1,21 @@
+    {\r
+        "policyConfigMessage": "Config Retrieved! ",\r
+        "policyConfigStatus": "CONFIG_RETRIEVED",\r
+        "type": "JSON",\r
+        "config": "{\"service\":\"ResourceRegionPolicy\",\"policyName\":\"bg4702.ResourceRegionPolicy_vhnportal_v1\",\"description\":\"ResourceRegionPolicy@CreatedBy:mh7921\",\"templateVersion\":\"1802V01\",\"version\":\"1802V01\",\"priority\":\"1\",\"riskType\":\"test\",\"riskLevel\":\"3\",\"guard\":\"False\",\"content\":{\"identity\":\"vhnPortalResourceRegion\",\"policyScope\":{\"serviceType\":[\"DHV\"],\"geoRegion\":[\"US\",\"INTERNATIONAL\"],\"subscriberRole\":[\"FFA Homing\"],\"networkType\":[\"ip\"],\"resourceInstanceType\":[\"Primary Service_Admin\",\"Secondary Service_Admin\"]},\"resourceRegionProperty\":{\"request\":\"{\\\"dhv_service_instance\\\": {\\\"get_param\\\": \\\"SERVICE_INST\\\"}, \\\"service_type\\\": \\\"vHNPortal\\\", \\\"e2evpnkey\\\": {\\\"get_param\\\": \\\"E2EVPNKEY\\\"}}\",\"controller\":\"SDN-C\"},\"type\":\"region_fit\",\"resourceInstanceType\":[\"Primary Service_Admin\",\"Secondary Service_Admin\"]}}",\r
+        "policyName": "bg4702.Config_MS_ResourceRegionPolicy_vhnportal_v1.1.xml",\r
+        "policyVersion": "1",\r
+        "matchingConditions": {\r
+            "serviceType": "DHV",\r
+            "ECOMPName": "SNIRO-Placement",\r
+            "ONAPName": "SNIRO-Placement",\r
+            "geoRegion": "US,INTERNATIONAL",\r
+            "service": "ResourceRegionPolicy",\r
+            "subscriberRole": "FFA Homing",\r
+            "type": "region_fit",\r
+            "networkType": "ip",\r
+            "resourceInstanceType": "Primary Service_Admin,Secondary Service_Admin"\r
+        },\r
+        "responseAttributes": {},\r
+        "property": null\r
+    }
\ No newline at end of file
diff --git a/test/placement-tests/testScoperequest.json b/test/placement-tests/testScoperequest.json
new file mode 100644 (file)
index 0000000..36f0c17
--- /dev/null
@@ -0,0 +1,144 @@
+{\r
+   "placementInfo": {\r
+      "serviceModelInfo": {\r
+         "modelVersion": "1.0",\r
+         "modelName": "vCPE",\r
+         "modelInvariantId": "250c90b4-42f9-4cd9-9270-fd33a0676f92",\r
+         "modelVersionId": "c233e7f3-bd70-4a2c-a88f-4f5743109e8d",\r
+         "modelType": "service"\r
+      },\r
+      "orderInfo":" {        \"requestParameters\": {            \"e2eVpnKey\": \"VPNL61657\",            \"dhvVendorName\": \"VELOCLOUD\",            \"dhvIPSec2TransportBandwidthUp\": \"10\",            \"vpnList\": [               {                  \"vpnInfo\": {                     \"pvcId\": \"5952413\",                     \"vpnId\": \"61657\"                  }               }           ],         \"dhvSiteEffectiveTransportBandwidth\": \"10\",            \"ucpeHostName\": \"US292IORLFL0102UJZZ01\",          \"commonSiteId\": \"90101124\",           \"dhvIPSec2TransportBandwidthDown\": \"10\",            \"vnfList\": [            {                \"vnfInfo\": {                    \"vnfType\": \"HN\",                    \"veloCloudNominalThroughput\": \"100\",                     \"vnfHostName\": \"US292IORLFL0102UVHN01\",                   \"vnfPartNumber\": \"DHV-VNF-VC-10M\",                    \"vnfManagementOption\": \"ATT\",                  \"vnfSoftwareVersion\": \"2.4.1\"                }             }            ]       }     }",\r
+      "serviceInstanceId": "4701bd3c-b722-4d07-abc0-183ea398fac5",\r
+      "demandInfo": {\r
+         "placementDemand": [\r
+            {\r
+               "tenantName": "",\r
+               "tenantId": "",\r
+               "serviceResourceId": "a297f69d-4d68-4d1f-8b06-be61bddf9e7f",\r
+               "resourceInstanceType": "vVIGaaS",\r
+               "resourceModuleName": "Primary Tunnel_XConn for DHV Testing_1 0",\r
+               "resourceModelInfo": {\r
+                  "modelVersion": "1.0",\r
+                  "modelName": "Tunnel_XConn for DHV Testing_1",\r
+                  "modelInvariantId": "b2ac0b6a-c157-4f27-a226-4fc6c1d5b08c",\r
+                  "modelCustomizationId": "8ade4a5f-a446-4b14-9d12-3ccdd80ef55c",\r
+                  "modelVersionId": "c3c3531a-a0c6-498f-8512-03793f7772fa",\r
+                  "modelType": "allottedResource"\r
+               }\r
+            },\r
+            {\r
+               "tenantName": "",\r
+               "tenantId": "",\r
+               "serviceResourceId": "73190cfb-e9de-4185-8f18-cb339df6b92a",\r
+               "resourceInstanceType": "vVIGaaS",\r
+               "resourceModuleName": "Secondary Tunnel_XConn for DHV Testing_1 1",\r
+               "resourceModelInfo": {\r
+                  "modelVersion": "1.0",\r
+                  "modelName": "Tunnel_XConn for DHV Testing_1",\r
+                  "modelInvariantId": "b2ac0b6a-c157-4f27-a226-4fc6c1d5b08c",\r
+                  "modelCustomizationId": "32b80123-84ea-4bda-82d9-4c70e812b450",\r
+                  "modelVersionId": "c3c3531a-a0c6-498f-8512-03793f7772fa",\r
+                  "modelType": "allottedResource"\r
+               }\r
+            },\r
+            {\r
+               "tenantName": "",\r
+               "tenantId": "",\r
+               "serviceResourceId": "f8489f98-db3d-4e84-9ec7-7f7b17b9857f",\r
+               "resourceInstanceType": "vHNPortalaaS",\r
+               "resourceModuleName": "Primary Service_Admin for DHV Test_1 0",\r
+               "resourceModelInfo": {\r
+                  "modelVersion": "1.0",\r
+                  "modelName": "Service_Admin for DHV Test_1",\r
+                  "modelInvariantId": "a8031455-34bc-4608-b731-973c258822d2",\r
+                  "modelCustomizationId": "bace7e9f-c0e7-4479-93df-aa10d387038b",\r
+                  "modelVersionId": "0e830d97-39fc-4310-a11d-ebab6c71b35e",\r
+                  "modelType": "allottedResource"\r
+               }\r
+            },\r
+            {\r
+               "tenantName": "",\r
+               "tenantId": "",\r
+               "serviceResourceId": "8a8973d4-3a91-4fe6-a846-6f4c282f9005",\r
+               "resourceInstanceType": "vHNPortalaaS",\r
+               "resourceModuleName": "Secondary Service_Admin for DHV Test_1 1",\r
+               "resourceModelInfo": {\r
+                  "modelVersion": "1.0",\r
+                  "modelName": "Service_Admin for DHV Test_1",\r
+                  "modelInvariantId": "a8031455-34bc-4608-b731-973c258822d2",\r
+                  "modelCustomizationId": "cb6d359d-8f83-41b6-b0cc-fb3cdf978e25",\r
+                  "modelVersionId": "0e830d97-39fc-4310-a11d-ebab6c71b35e",\r
+                  "modelType": "allottedResource"\r
+               }\r
+            },\r
+            {\r
+               "tenantName": "",\r
+               "tenantId": "",\r
+               "serviceResourceId": "3f2b0c6d-6867-4369-b597-d929305da414",\r
+               "resourceInstanceType": "vHNGWaaS",\r
+               "resourceModuleName": "Primary IP_Mux_Demux updated_1 0",\r
+               "resourceModelInfo": {\r
+                  "modelVersion": "1.0",\r
+                  "modelName": "IP_Mux_Demux updated_1",\r
+                  "modelInvariantId": "72ad23e8-575d-4bc1-a88d-bb63ca66b85f",\r
+                  "modelCustomizationId": "925db703-945a-4b14-aafa-607c99c32f46",\r
+                  "modelVersionId": "cb760674-1c09-4316-837f-1ee1e816c26f",\r
+                  "modelType": "allottedResource"\r
+               }\r
+            },\r
+            {\r
+               "tenantName": "",\r
+               "tenantId": "",\r
+               "serviceResourceId": "caea369e-90e6-4bf0-9aa4-c80ffb10c77e",\r
+               "resourceInstanceType": "vHNGWaaS",\r
+               "resourceModuleName": "Secondary IP_Mux_Demux updated_1 1",\r
+               "resourceModelInfo": {\r
+                  "modelVersion": "1.0",\r
+                  "modelName": "IP_Mux_Demux updated_1",\r
+                  "modelInvariantId": "72ad23e8-575d-4bc1-a88d-bb63ca66b85f",\r
+                  "modelCustomizationId": "5f5793d7-843c-4f8e-b01d-35ece0b17ead",\r
+                  "modelVersionId": "cb760674-1c09-4316-837f-1ee1e816c26f",\r
+                  "modelType": "allottedResource"\r
+               }\r
+            }\r
+         ]\r
+      },\r
+      "subscriberInfo": {\r
+         "subscriberCommonSiteId": null,\r
+         "globalSubscriberId": "300NCQ",\r
+         "subscriberName": "Test Customer"\r
+      },\r
+      "policyId": [\r
+         "SNIRO.DistanceToLocationPolicy_vhngw",\r
+         "SNIRO.VNFPolicy_vhngatewayprimary1_v1",\r
+         "SNIRO.ResourceInstancePolicy_hngateway",\r
+         "SNIRO.ResourceRegionPolicy_hngateway_v1",\r
+         "SNIRO.VNFPolicy_vhngatewaysecondary1_v1",\r
+         "SNIRO.ZonePolicy_vhngw",\r
+         "SNIRO.PlacementOptimizationPolicy_dhv_v3",\r
+         "SNIRO.VNFPolicy_vhnportal_primary1_v1",\r
+         "SNIRO.ResourceInstancePolicy_vhnportal_v3",\r
+         "SNIRO.ResourceRegionPolicy_vhnportal_v1",\r
+         "SNIRO.VNFPolicy_vhnportalsecondary1_v1",\r
+         "SNIRO.ZonePolicy_vhnportal",\r
+         "SNIRO.DistanceToLocationPolicy_vvig",\r
+         "SNIRO.InventoryGroupPolicy_vvig",\r
+         "SNIRO.VNFPolicy_vvigprimary1_v1",\r
+         "SNIRO.ResourceInstancePolicy_vvig",\r
+         "SNIRO.VNFPolicy_vvigsecondary1_v1"\r
+      ]\r
+   },\r
+   "requestInfo": {\r
+      "transactionId": "264e9db9-6d59-4888-9c90-51245d7c811f",\r
+      "sourceId": "mso",\r
+      "requestType": "initial",\r
+      "callbackUrl": "http://127.0.0.1:7001",\r
+      "requestId": "264e9db9-6d59-4888-9c90-51245d7c811f",\r
+      "optimizer": [\r
+         "placement",\r
+         "license"\r
+      ],\r
+      "numSolutions": 1,\r
+      "timeout": 1800\r
+   }\r
+}\r
diff --git a/test/placement-tests/test_by_scope.yaml b/test/placement-tests/test_by_scope.yaml
new file mode 100644 (file)
index 0000000..0b53e5f
--- /dev/null
@@ -0,0 +1,20 @@
+policy_info:
+    placement:
+        policy_fetch: by_scope
+        policy_scope:
+            default_scope: XXX_1802
+            scope_vcpe: oof_beijing
+            service_name: placementInfo.serviceModelInfo.modelName
+        policy_subscriber: SubscriberPolicy
+        subscriber_name: placementInfo.subscriberInfo.subscriberName
+        policy_type_vcpe:
+            - CloudAttributePolicy
+            - DistanceToLocationPolicy
+            - instanceReservationPolicy
+            - PlacementOptimizationPolicy
+            - ResourceInstancePolicy
+            - VNFPolicy
+            - ZonePolicy
+    default:  # if no explicit service related information is needed
+        policy_fetch: by_name
+        policy_scope: none
diff --git a/test/placement-tests/vnfGroupPolicies.txt b/test/placement-tests/vnfGroupPolicies.txt
new file mode 100644 (file)
index 0000000..16aca6c
--- /dev/null
@@ -0,0 +1,197 @@
+[\r
+  {\r
+    "content": {\r
+      "identity": "vhngateway-pri-sec-1",\r
+      "policyScope": {\r
+        "geoRegion": [\r
+          "US",\r
+          "INTERNATIONAL"\r
+        ],\r
+        "networkType": [\r
+          "ip"\r
+        ],\r
+        "resourceInstanceType": [\r
+          "Primary IP_Mux_Demux",\r
+          "Secondary IP_Mux_Demux"\r
+        ],\r
+        "serviceType": [\r
+          "DHV"\r
+        ],\r
+        "subscriberRole": [\r
+          "FFA Homing"\r
+        ]\r
+      },\r
+      "property": [\r
+        {\r
+          "attributes": {\r
+            "equipmentRole": "",\r
+            "globalCustomerId": "",\r
+            "modelInvariantId": "",\r
+            "modelVersionId": "",\r
+            "operationalStatus": "out-of-service-path",\r
+            "orchestrationStatus": [\r
+              "Activate",\r
+              "Activated"\r
+            ]\r
+          },\r
+          "inventoryProvider": "aai",\r
+          "inventoryType": "cloud"\r
+        },\r
+        {\r
+          "attributes": {\r
+            "equipmentRole": "",\r
+            "globalCustomerId": "21014aa2-526b-11e6-beb8-9e71128cae77",\r
+            "modelInvariantId": "",\r
+            "modelVersionId": "",\r
+            "operationalStatus": "out-of-service-path",\r
+            "orchestrationStatus": [\r
+              "Activate",\r
+              "Activated"\r
+            ]\r
+          },\r
+          "inventoryProvider": "aai",\r
+          "inventoryType": "service"\r
+        }\r
+      ],\r
+      "resourceInstanceType": [\r
+        "Primary IP_Mux_Demux",\r
+        "Secondary IP_Mux_Demux"\r
+      ],\r
+      "type": "vnfPolicy"\r
+    },\r
+    "description": "VNFPolicy@CreatedBy:mh7921",\r
+    "guard": "False",\r
+    "policyName": "bg4702.VNFPolicy_vhngatewayprimary_v1",\r
+    "priority": "1",\r
+    "riskLevel": "3",\r
+    "riskType": "test",\r
+    "service": "VNFPolicy",\r
+    "templateVersion": "1802V01",\r
+    "version": "1802V01"\r
+  },\r
+  {\r
+    "content": {\r
+      "identity": "vhnportal-pri-sec-1",\r
+      "policyScope": {\r
+        "geoRegion": [\r
+          "US",\r
+          "INTERNATIONAL"\r
+        ],\r
+        "networkType": [\r
+          "ip"\r
+        ],\r
+        "resourceInstanceType": [\r
+          "Primary Service_Admin",\r
+          "Secondary Service_Admin"\r
+        ],\r
+        "serviceType": [\r
+          "DHV"\r
+        ],\r
+        "subscriberRole": [\r
+          "FFA Homing"\r
+        ]\r
+      },\r
+      "property": [\r
+        {\r
+          "attributes": {\r
+            "equipmentRole": "",\r
+            "globalCustomerId": "",\r
+            "modelInvariantId": "",\r
+            "modelVersionId": "",\r
+            "operationalStatus": "out-of-service-path",\r
+            "orchestrationStatus": [\r
+              "Activate",\r
+              "Activated"\r
+            ]\r
+          },\r
+          "inventoryProvider": "aai",\r
+          "inventoryType": "cloud"\r
+        },\r
+        {\r
+          "attributes": {\r
+            "equipmentRole": "",\r
+            "globalCustomerId": "21014aa2-526b-11e6-beb8-9e71128cae77",\r
+            "modelInvariantId": "",\r
+            "modelVersionId": "",\r
+            "operationalStatus": "out-of-service-path",\r
+            "orchestrationStatus": [\r
+              "Activate",\r
+              "Activated"\r
+            ]\r
+          },\r
+          "inventoryProvider": "aai",\r
+          "inventoryType": "service"\r
+        }\r
+      ],\r
+      "resourceInstanceType": [\r
+        "Primary Service_Admin",\r
+        "Secondary Service_Admin"\r
+      ],\r
+      "type": "vnfPolicy"\r
+    },\r
+    "description": "VNFPolicy@CreatedBy:mh7921",\r
+    "guard": "False",\r
+    "policyName": "bg4702.VNFPolicy_vhnportal_primary_v1",\r
+    "priority": "1",\r
+    "riskLevel": "3",\r
+    "riskType": "test",\r
+    "service": "VNFPolicy",\r
+    "templateVersion": "1802V01",\r
+    "version": "1802V01"\r
+  },\r
+  {\r
+    "content": {\r
+      "identity": "vvig-pri-sec-1",\r
+      "policyScope": {\r
+        "geoRegion": [\r
+          "US",\r
+          "INTERNATIONAL"\r
+        ],\r
+        "networkType": [\r
+          "ip"\r
+        ],\r
+        "resourceInstanceType": [\r
+          "Primary Tunnel_XConn",\r
+          "Secondary Tunnel_XConn"\r
+        ],\r
+        "serviceType": [\r
+          "DHV"\r
+        ],\r
+        "subscriberRole": [\r
+          "FFA Homing"\r
+        ]\r
+      },\r
+      "property": [\r
+        {\r
+          "attributes": {\r
+            "equipmentRole": "",\r
+            "globalCustomerId": "21014aa2-526b-11e6-beb8-9e71128cae77",\r
+            "modelInvariantId": "",\r
+            "modelVersionId": "",\r
+            "operationalStatus": "out-of-service-path",\r
+            "orchestrationStatus": [\r
+              "Activate",\r
+              "Activated"\r
+            ]\r
+          },\r
+          "inventoryProvider": "aai",\r
+          "inventoryType": "service"\r
+        }\r
+      ],\r
+      "resourceInstanceType": [\r
+        "Primary Tunnel_XConn",\r
+        "Secondary Tunnel_XConn"\r
+      ],\r
+      "type": "vnfPolicy"\r
+    },\r
+    "description": "VNFPolicy@CreatedBy:mh7921",\r
+    "guard": "False",\r
+    "policyName": "bg4702.VNFPolicy_vvig1_v1",\r
+    "priority": "1",\r
+    "riskLevel": "3",\r
+    "riskType": "test",\r
+    "service": "VNFPolicy",\r
+    "templateVersion": "1802V01",\r
+    "version": "1802V01"\r
+  }\r
+]
\ No newline at end of file
diff --git a/test/policy-local-files/CloudAttributePolicy_vGMuxInfra_1.json b/test/policy-local-files/CloudAttributePolicy_vGMuxInfra_1.json
new file mode 100644 (file)
index 0000000..57c0039
--- /dev/null
@@ -0,0 +1,34 @@
+{
+    "service": "CloudAttributePolicy",
+    "policyName": "CloudAttributePolicy_vGMuxInfra",
+    "description": "Attribute policy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "3",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vGMuxInfra_cloud_attributes",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vGMuxInfra"]
+        },
+        "cloudAttributeProperty": {
+            "networkRoles": {
+                "all": [
+                       "vGMuxInfra.OAM",
+                      "vGMuxInfra.SR_IOV_Provider2_1",
+                      "vGMuxInfra.SR_IOV_Provider2_2"
+                ]
+            },
+            "complex": {
+                "any": [  ]
+            }
+        },
+        "type": "attribute",
+        "resourceInstanceType": ["vGMuxInfra"]
+    }
+}
diff --git a/test/policy-local-files/CloudAttributePolicy_vG_1.json b/test/policy-local-files/CloudAttributePolicy_vG_1.json
new file mode 100644 (file)
index 0000000..cbe2a88
--- /dev/null
@@ -0,0 +1,34 @@
+{
+    "service": "CloudAttributePolicy",
+    "policyName": "cloud AttributePolicy_vG",
+    "description": "Attribute policy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "10",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vG_cloud_attributes",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vG"]
+        },
+        "cloudAttributeProperty": {
+            "networkRoles": {
+                "all": [
+                       "vG.OAM",
+                      "vG.SR_IOV_Provider2_1",
+                      "vG.SR_IOV_Provider2_2"
+                ]
+            },
+            "complex": {
+                "any": [  ]
+            }
+        },
+        "type": "attribute",
+        "resourceInstanceType": ["vG"]
+    }
+}
diff --git a/test/policy-local-files/DistanceToLocationPolicy_vGMuxInfra_1.json b/test/policy-local-files/DistanceToLocationPolicy_vGMuxInfra_1.json
new file mode 100644 (file)
index 0000000..414c167
--- /dev/null
@@ -0,0 +1,30 @@
+{
+    "service": "DistanceToLocationPolicy",
+    "policyName": "DistanceToLocationPolicy_vGMuxInfra",
+    "description": "DistanceToLocationPolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "3",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+        "distanceToLocationProperty": {
+            "locationInfo": "customer_loc",
+            "distanceCondition": {
+                "parameter": "distance",
+                "value": "50000 km",
+                "operator": "less"
+            }
+        },
+        "identity": "distance-vGMuxInfra",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vGMuxInfra"]
+        },
+        "type": "distance_to_location",
+        "resourceInstanceType": ["vGMuxInfra"]
+    }
+}
diff --git a/test/policy-local-files/DistanceToLocationPolicy_vG_1.json b/test/policy-local-files/DistanceToLocationPolicy_vG_1.json
new file mode 100644 (file)
index 0000000..737ee19
--- /dev/null
@@ -0,0 +1,30 @@
+{
+    "service": "DistanceToLocationPolicy",
+    "policyName": "DistanceToLocationPolicy_vG",
+    "description": "DistanceToLocationPolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "3",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+        "distanceToLocationProperty": {
+            "locationInfo": "customer_loc",
+            "distanceCondition": {
+                "parameter": "distance",
+                "value": "50000 km",
+                "operator": "less"
+            }
+        },
+        "identity": "distance-vG",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vG"]
+        },
+        "type": "distance_to_location",
+        "resourceInstanceType": ["vG"]
+    }
+}
diff --git a/test/policy-local-files/InventoryGroup_vGMuxInfra_1.json b/test/policy-local-files/InventoryGroup_vGMuxInfra_1.json
new file mode 100644 (file)
index 0000000..20ff7f7
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "service": "InventoryGroupPolicy",
+    "policyName": "InventoryGroupPolicy_vGMuxInfra",
+    "description": "InventoryGroupPolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "6",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vGMuxInfra-pri-sec-2",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vGMuxInfra"]
+        },
+        "type": "inventory_group",
+        "resourceInstanceType": ["vGMuxInfra"]
+    }
+}
diff --git a/test/policy-local-files/InventoryGroup_vG_1.json b/test/policy-local-files/InventoryGroup_vG_1.json
new file mode 100644 (file)
index 0000000..99ae309
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "service": "InventoryGroupPolicy",
+    "policyName": "InventoryGroupPolicy_vG",
+    "description": "InventoryGroupPolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "6",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vG-pri-sec-1",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vG"]
+        },
+        "type": "inventory_group",
+        "resourceInstanceType": ["vG"]
+    }
+}
diff --git a/test/policy-local-files/PlacementOptimizationPolicy.json b/test/policy-local-files/PlacementOptimizationPolicy.json
new file mode 100644 (file)
index 0000000..7c43435
--- /dev/null
@@ -0,0 +1,41 @@
+{
+    "service": "PlacementOptimizationPolicy",
+    "policyName": "PlacementOptimizationPolicy",
+    "description": "PlacementOptimizationPolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "objectiveParameter": {
+            "parameterAttributes": [
+                {
+                    "resource": ["vGMuxInfra"],
+                    "customerLocationInfo": "customer_loc",
+                    "parameter": "distance",
+                    "weight": "2",
+                    "operator": "product"
+                },
+                {
+                    "resource": ["vG"],
+                    "customerLocationInfo": "customer_loc",
+                    "parameter": "distance",
+                    "weight": "1",
+                    "operator": "product"
+                }
+            ],
+            "operator": "sum"
+        },
+        "identity": "optimization",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vGMuxInfra","vG"]
+        },
+        "type": "placementOptimization",
+        "objective": "minimize"
+    }
+}
diff --git a/test/policy-local-files/ResourceInstancePolicy_vG_1.json b/test/policy-local-files/ResourceInstancePolicy_vG_1.json
new file mode 100644 (file)
index 0000000..21ae0e4
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "service": "ResourceInstancePolicy",
+    "policyName": "ResourceInstancePolicy_vG",
+    "description": "ResourceInstancePolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vG-resourceInstance",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vG", "vGMuxInfra"]
+        },
+        "resourceInstanceProperty": {
+                   "request": "{\"test\": \"123\"}",
+            "controller": "SDN-C"
+        },
+        "type": "instance_fit",
+        "resourceInstanceType": ["vG", "vGMuxInfra"]
+    }
+}
diff --git a/test/policy-local-files/VNFPolicy_vGMuxInfra_1.json b/test/policy-local-files/VNFPolicy_vGMuxInfra_1.json
new file mode 100644 (file)
index 0000000..b0963d6
--- /dev/null
@@ -0,0 +1,36 @@
+{
+    "service": "VNFPolicy",
+    "policyName": "VNFPolicy_vGMuxInfra",
+    "description": "VNFPolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "6",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vGMuxInfra-pri-sec-1",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vGMuxInfra"]
+        },
+        "property": [
+            {
+                "inventoryProvider": "aai",
+                "serviceType": "",
+                "inventoryType": "cloud",
+                "customerId": ""
+            },
+            {
+                "inventoryProvider": "aai",
+                "serviceType": "vGMuxInfraaaS",
+                "inventoryType": "service",
+                "customerId": "21014aa2-526b-11e6-beb8-9e71128cae77"
+            }
+        ],
+        "type": "vnfPolicy",
+        "resourceInstanceType": ["vGMuxInfra"]
+    }
+}
diff --git a/test/policy-local-files/VNFPolicy_vG_1.json b/test/policy-local-files/VNFPolicy_vG_1.json
new file mode 100644 (file)
index 0000000..de0a158
--- /dev/null
@@ -0,0 +1,36 @@
+{
+    "service": "VNFPolicy",
+    "policyName": "VNFPolicy_vG",
+    "description": "VNFPolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "6",
+    "riskType": "test",
+    "riskLevel": "3",
+    "guard": "False",
+    "content": {
+        "identity": "vG-pri-sec-1",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vG"]
+        },
+        "property": [
+            {
+                "inventoryProvider": "aai",
+                "serviceType": "",
+                "inventoryType": "cloud",
+                "customerId": " "
+            },
+            {
+                "inventoryProvider": "aai",
+                "serviceType": "vGaaS",
+                "inventoryType": "service",
+                "customerId": "21014aa2-526b-11e6-beb8-9e71128cae77"
+           }
+       ],
+        "type": "vnfPolicy",
+        "resourceInstanceType": ["vG"]
+    }
+}
diff --git a/test/policy-local-files/ZonePolicy_vGMuxInfra_1.json b/test/policy-local-files/ZonePolicy_vGMuxInfra_1.json
new file mode 100644 (file)
index 0000000..9f941e4
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "service": "ZonePolicy",
+    "policyName": "ZonePolicy_vGMuxInfra",
+    "description": "ZonePolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+        "identity": "zone-vGMuxInfra",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vGMuxInfra"]
+        },
+        "zoneProperty": {
+            "qualifier": "different",
+            "category": "complex"
+        },
+        "type": "zone",
+        "resourceInstanceType": ["vGMuxInfra"]
+    }
+}
diff --git a/test/policy-local-files/ZonePolicy_vG_1.json b/test/policy-local-files/ZonePolicy_vG_1.json
new file mode 100644 (file)
index 0000000..8104f6b
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "service": "ZonePolicy",
+    "policyName": "ZonePolicy_vG",
+    "description": "ZonePolicy",
+    "templateVersion": "1702.03",
+    "version": "1707",
+    "priority": "5",
+    "riskType": "test",
+    "riskLevel": "2",
+    "guard": "False",
+    "content": {
+        "identity": "zone-vG",
+        "policyScope": {
+            "serviceType": ["vCPE"],
+            "geoRegion": ["US", "INTERNATIONAL"],
+            "networkType": ["ip"],
+            "resourceInstanceType": ["vG"]
+        },
+        "zoneProperty": {
+            "qualifier": "different",
+            "category": "complex"
+        },
+        "type": "zone",
+        "resourceInstanceType": ["vG"]
+    }
+}
diff --git a/test/test-requirements.txt b/test/test-requirements.txt
new file mode 100644 (file)
index 0000000..b16a37e
--- /dev/null
@@ -0,0 +1,4 @@
+coverage
+moto
+pytest
+pytest-tap
diff --git a/test/test_ConductorApiBuilder.py b/test/test_ConductorApiBuilder.py
new file mode 100644 (file)
index 0000000..b988efa
--- /dev/null
@@ -0,0 +1,39 @@
+import unittest
+import json
+import yaml
+from osdf.optimizers.placementopt.conductor.api_builder import conductor_api_builder
+
+
+class TestConductorApiBuilder(unittest.TestCase):
+
+    def test_conductor_api_call_builder(self):
+        #main_dir = ".."
+        main_dir = ""
+        conductor_api_template = main_dir + "osdf/templates/conductor_interface.json"
+        parameter_data_file = main_dir + "test/placement-tests/request.json"
+        policy_data_path = main_dir + "test/policy-local-files/"
+        local_config_file = main_dir + "config/common_config.yaml"
+
+        policy_data_files = ["CloudAttributePolicy_vGMuxInfra_1.json",
+                            "CloudAttributePolicy_vG_1.json",
+                            "DistanceToLocationPolicy_vGMuxInfra_1.json",
+                            "DistanceToLocationPolicy_vG_1.json",
+                            "InventoryGroup_vGMuxInfra_1.json",
+                            "InventoryGroup_vG_1.json",
+                            "PlacementOptimizationPolicy.json",
+                            "ResourceInstancePolicy_vG_1.json",
+                            "VNFPolicy_vGMuxInfra_1.json",
+                            "VNFPolicy_vG_1.json",
+                            "ZonePolicy_vGMuxInfra_1.json",
+                            "ZonePolicy_vG_1.json"]
+        request_json = json.loads(open(parameter_data_file).read())
+        policies = [json.loads(open(policy_data_path + file).read()) for file in policy_data_files]
+        local_config = yaml.load(open(local_config_file))
+        templ_string = conductor_api_builder(request_json, policies, local_config, [], conductor_api_template)
+        templ_json = json.loads(templ_string)
+        self.assertEqual(templ_json["name"], "yyy-yyy-yyyy")
+
+
+if __name__ == "__main__":
+    unittest.main()
+
diff --git a/test/test_PolicyCalls.py b/test/test_PolicyCalls.py
new file mode 100644 (file)
index 0000000..b05b6dc
--- /dev/null
@@ -0,0 +1,115 @@
+import json
+import unittest
+
+from osdf.config.base import osdf_config
+from osdf.adapters.policy import interface
+from osdf.utils.interfaces import RestClient
+import yaml
+from mock import patch
+from osdf.optimizers.placementopt.conductor import translation
+
+
+class TestPolicyCalls(unittest.TestCase):
+        
+    def test_get_subscriber_name(self):
+        req_json_obj = json.loads(open("./test/placement-tests/request_mso.json").read())
+        config_core = osdf_config.core
+        pmain = config_core['policy_info']['placement']
+        print(pmain)
+        subs_name = interface.get_subscriber_name(req_json_obj, pmain)
+        print("subscriber_name=", subs_name)
+        self.assertEquals(subs_name, "Avteet_Chayal")
+    
+    
+    def test_get_subscriber_name_null(self):
+        req_json_file = "./test/placement-tests/request_mso_subs_name_null.json"
+        req_json_obj = json.loads(open(req_json_file).read())
+        config_core = osdf_config.core
+        
+        pmain = config_core['policy_info']['placement']
+        print(pmain)
+        subs_name = interface.get_subscriber_name(req_json_obj, pmain)
+        print("subscriber_name=", subs_name)
+        self.assertEquals(subs_name, "DEFAULT")
+        
+    
+    def test_get_subscriber_name_blank(self):
+        req_json_file = "./test/placement-tests/request_mso_subs_name_blank.json"
+        req_json_obj = json.loads(open(req_json_file).read())
+        config_core = osdf_config.core
+        
+        pmain = config_core['policy_info']['placement']
+        print(pmain)
+        subs_name = interface.get_subscriber_name(req_json_obj, pmain)
+        print("subscriber_name=", subs_name)
+        self.assertEquals(subs_name, "DEFAULT")
+        
+    
+    def test_get_subscriber_name_default(self):
+        req_json_file = "./test/placement-tests/request_mso_subs_name_default.json"
+        req_json_obj = json.loads(open(req_json_file).read())
+        config_core = osdf_config.core
+        
+        pmain = config_core['policy_info']['placement']
+        print(pmain)
+        subs_name = interface.get_subscriber_name(req_json_obj, pmain)
+        print("subscriber_name=", subs_name)
+        self.assertEquals(subs_name, "DEFAULT")
+    
+    
+    def test_get_subscriber_name_none(self):
+        req_json_file = "./test/placement-tests/request_mso_subs_name_none.json"
+        req_json_obj = json.loads(open(req_json_file).read())
+        config_core = osdf_config.core
+        
+        pmain = config_core['policy_info']['placement']
+        print(pmain)
+        subs_name = interface.get_subscriber_name(req_json_obj, pmain)
+        print("subscriber_name=", subs_name)
+        self.assertEquals(subs_name, "DEFAULT")
+        
+    
+    def test_get_by_scope(self):
+        req_json_file = "./test/placement-tests/testScoperequest.json"
+        allPolicies = "./test/placement-tests/scopePolicies.json"
+        req_json_obj = json.loads(open(req_json_file).read())
+        req_json_obj2 = json.loads(open(allPolicies).read())
+        config_core = osdf_config.core
+        yamlFile = "./test/placement-tests/test_by_scope.yaml"
+        
+        with open(yamlFile) as yamlFile2:
+            policyConfigFile = yaml.load(yamlFile2)
+            with patch('osdf.adapters.policy.interface.get_subscriber_role', return_value=('FFA Homing', [])) as mock_open:
+                with patch('osdf.utils.interfaces.RestClient.request', return_value = req_json_obj2):
+                    policiesList = interface.get_by_scope(RestClient, req_json_obj, policyConfigFile, 'placement')
+                    print(policiesList)
+                    #catches Exception if policiesList is null
+                    self.assertTrue(policiesList, 'is null')
+                    self.assertRaises(Exception)
+    
+    def test_gen_demands(self):
+        actionsList = []
+        genDemandslist = []
+        req_json = "./test/placement-tests/testScoperequest.json"
+        policiesList = "./test/placement-tests/vnfGroupPolicies.txt"
+        fh = json.loads(open(policiesList).read())
+        #print(fh)
+        req_json = json.loads(open(req_json).read())
+        config_core = osdf_config.core
+        service_type = req_json['placementInfo'].get('serviceType', None)
+        # service_type = data_mapping.get_request_service_type(req_json_file)
+        genDemands = translation.gen_demands(req_json['placementInfo']['demandInfo'], fh)
+        #print(genDemands)
+        #print(req_json_file['placementInfo']['demandInfo']['placementDemand'][0])
+        for action in req_json['placementInfo']['demandInfo']['placementDemand']:
+            #print(action['resourceModuleName'])
+            actionsList.append(action['resourceModuleName'])
+        for key2,value in genDemands.items():
+            #print(key2)
+            genDemandslist.append(key2)
+        #genDemandslist.remove('Primary IP_Mux_Demux updated_1 0')
+        #catches Exception if lists are not equal
+        self.assertListEqual(genDemandslist, actionsList, 'generated demands are not equal to the passed input [placementDemand][resourceModuleName] list')
+           
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tox.ini b/tox.ini
new file mode 100644 (file)
index 0000000..309296d
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,17 @@
+
+[tox]
+skipsdist=True
+envlist = py3
+
+[testenv]
+distribute = False
+commands =
+    coverage run --module pytest 
+    coverage report --omit=".tox/py3/*","test/*"
+    # TODO: need to update the above "omit" when we package osdf as pip-installable
+    # coverage html --omit=.tox/py3/* -d htmlcov
+deps = -r{toxinidir}/requirements.txt 
+    -r{toxinidir}/test/test-requirements.txt
+
+[testenv:py3]
+basepython=python3.6