aboutsummaryrefslogtreecommitdiffstats
path: root/osdf
diff options
context:
space:
mode:
authorvrvarma <vv8305@att.com>2019-12-13 10:24:55 -0500
committervrvarma <vv8305@att.com>2019-12-13 10:29:45 -0500
commit430153e1a9489a86cf0ff7942eceb0bf5f1c170c (patch)
treeb22090b80d11761a24d9cbeaa6348704cce2de83 /osdf
parent34ba229b31758c38a299a163de0007848b5921be (diff)
osdf rearchitecture into apps and libs
Change-Id: I2db2f8e252bd5e60807b2ffabf5a5b193a789f7a Signed-off-by: vrvarma <vv8305@att.com> Issue-ID: OPTFRA-637
Diffstat (limited to 'osdf')
-rw-r--r--osdf/apps/__init__.py2
-rw-r--r--osdf/apps/baseapp.py166
-rw-r--r--osdf/config/__init__.py2
-rwxr-xr-xosdf/logging/osdf_logging.py1
-rw-r--r--osdf/models/api/pciOptimizationRequest.py54
-rw-r--r--osdf/models/api/pciOptimizationResponse.py46
-rw-r--r--osdf/models/api/placementRequest.py105
-rw-r--r--osdf/models/api/placementResponse.py64
-rw-r--r--osdf/optimizers/licenseopt/simple_license_allocation.py43
-rw-r--r--osdf/optimizers/pciopt/configdb.py69
-rw-r--r--osdf/optimizers/pciopt/pci_opt_processor.py122
-rw-r--r--osdf/optimizers/pciopt/solver/__init__.py0
-rw-r--r--osdf/optimizers/pciopt/solver/min_confusion.mzn98
-rw-r--r--osdf/optimizers/pciopt/solver/min_confusion_inl.mzn140
-rw-r--r--osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn86
-rw-r--r--osdf/optimizers/pciopt/solver/optimizer.py137
-rw-r--r--osdf/optimizers/pciopt/solver/pci_utils.py40
-rw-r--r--osdf/optimizers/placementopt/conductor/__init__.py17
-rw-r--r--osdf/optimizers/placementopt/conductor/api_builder.py99
-rwxr-xr-xosdf/optimizers/placementopt/conductor/conductor.py202
-rw-r--r--osdf/optimizers/placementopt/conductor/remote_opt_processor.py81
-rw-r--r--osdf/optimizers/placementopt/conductor/translation.py283
-rw-r--r--osdf/optimizers/routeopt/simple_route_opt.py153
-rwxr-xr-xosdf/templates/cms_opt_request.jsont35
-rwxr-xr-xosdf/templates/cms_opt_request.jsont_1707_v167
-rwxr-xr-xosdf/templates/cms_opt_request_1702.jsont63
-rw-r--r--osdf/templates/cms_opt_response.jsont8
-rwxr-xr-xosdf/templates/conductor_interface.json39
-rw-r--r--osdf/templates/license_opt_request.jsont6
-rwxr-xr-xosdf/templates/plc_opt_request.jsont142
-rwxr-xr-xosdf/templates/plc_opt_response.jsont10
-rwxr-xr-xosdf/templates/policy_request.jsont3
-rwxr-xr-xosdf/templates/test_cms_nb_req_from_client.jsont19
-rwxr-xr-xosdf/templates/test_plc_nb_req_from_client.jsont52
-rw-r--r--osdf/utils/mdc_utils.py8
35 files changed, 177 insertions, 2285 deletions
diff --git a/osdf/apps/__init__.py b/osdf/apps/__init__.py
new file mode 100644
index 0000000..370bc06
--- /dev/null
+++ b/osdf/apps/__init__.py
@@ -0,0 +1,2 @@
+import yaml
+yaml.warnings({'YAMLLoadWarning': False}) \ No newline at end of file
diff --git a/osdf/apps/baseapp.py b/osdf/apps/baseapp.py
new file mode 100644
index 0000000..cfa7e5d
--- /dev/null
+++ b/osdf/apps/baseapp.py
@@ -0,0 +1,166 @@
+# -------------------------------------------------------------------------
+# 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.
+#
+# -------------------------------------------------------------------------
+#
+
+"""
+OSDF Manager Main Flask Application
+"""
+
+import json
+import ssl
+import sys
+import time
+import traceback
+from optparse import OptionParser
+
+import pydevd
+from flask import Flask, request, Response, g
+from requests import RequestException
+from schematics.exceptions import DataError
+
+import osdf.adapters.aaf.sms as sms
+import osdf.operation.responses
+from osdf.config.base import osdf_config
+from osdf.logging.osdf_logging import error_log, debug_log
+from osdf.operation.error_handling import request_exception_to_json_body, internal_error_message
+from osdf.operation.exceptions import BusinessException
+from osdf.utils.mdc_utils import clear_mdc, mdc_from_json, default_mdc
+
+ERROR_TEMPLATE = osdf.ERROR_TEMPLATE
+
+app = Flask(__name__)
+
+BAD_CLIENT_REQUEST_MESSAGE = 'Client sent an invalid request'
+
+
+@app.errorhandler(BusinessException)
+def handle_business_exception(e):
+ """An exception explicitly raised due to some business rule"""
+ error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
+ err_msg = ERROR_TEMPLATE.render(description=str(e))
+ response = Response(err_msg, content_type='application/json; charset=utf-8')
+ response.status_code = 400
+ return response
+
+
+@app.errorhandler(RequestException)
+def handle_request_exception(e):
+ """Returns a detailed synchronous message to the calling client
+ when osdf fails due to a remote call to another system"""
+ error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
+ err_msg = request_exception_to_json_body(e)
+ response = Response(err_msg, content_type='application/json; charset=utf-8')
+ response.status_code = 400
+ return response
+
+
+@app.errorhandler(DataError)
+def handle_data_error(e):
+ """Returns a detailed message to the calling client when the initial synchronous message is invalid"""
+ error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
+
+ body_dictionary = {
+ "serviceException": {
+ "text": BAD_CLIENT_REQUEST_MESSAGE,
+ "exceptionMessage": str(e.errors),
+ "errorType": "InvalidClientRequest"
+ }
+ }
+
+ body_as_json = json.dumps(body_dictionary)
+ response = Response(body_as_json, content_type='application/json; charset=utf-8')
+ response.status_code = 400
+ return response
+
+
+@app.before_request
+def log_request():
+ g.request_start = time.clock()
+ if request.get_json():
+
+ request_json = request.get_json()
+ g.request_id = request_json['requestInfo']['requestId']
+ mdc_from_json(request_json)
+ else:
+ g.request_id = "N/A"
+ default_mdc()
+
+
+
+@app.after_request
+def log_response(response):
+ clear_mdc()
+ return response
+
+
+@app.errorhandler(500)
+def internal_failure(error):
+ """Returned when unexpected coding errors occur during initial synchronous processing"""
+ error_log.error("Synchronous error for request id {} {}".format(g.request_id, traceback.format_exc()))
+ response = Response(internal_error_message, content_type='application/json; charset=utf-8')
+ response.status_code = 500
+ return response
+
+
+def get_options(argv):
+ program_version_string = '%%prog %s' % "v1.0"
+ program_longdesc = ""
+ program_license = ""
+
+ parser = OptionParser(version=program_version_string, epilog=program_longdesc, description=program_license)
+ parser.add_option("-l", "--local", dest="local", help="run locally", action="store_true", default=False)
+ parser.add_option("-t", "--devtest", dest="devtest", help="run in dev/test environment", action="store_true",
+ default=False)
+ parser.add_option("-d", "--debughost", dest="debughost", help="IP Address of host running debug server", default='')
+ parser.add_option("-p", "--debugport", dest="debugport", help="Port number of debug server", type=int, default=5678)
+ opts, args = parser.parse_args(argv)
+
+ if opts.debughost:
+ debug_log.debug('pydevd.settrace({}, port={})'.format(opts.debughost, opts.debugport))
+ pydevd.settrace(opts.debughost, port=opts.debugport)
+ return opts
+
+
+def build_ssl_context():
+ ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
+ ssl_context.set_ciphers('ECDHE-RSA-AES128-SHA256:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH')
+ ssl_context.load_cert_chain(sys_conf['ssl_context'][0], sys_conf['ssl_context'][1])
+ return ssl_context
+
+
+def run_app():
+ global sys_conf
+ sys_conf = osdf_config['core']['osdf_system']
+ ports = sys_conf['osdf_ports']
+ internal_port, external_port = ports['internal'], ports['external']
+ local_host = sys_conf['osdf_ip_default']
+ common_app_opts = dict(host=local_host, threaded=True, use_reloader=False)
+ ssl_opts = sys_conf.get('ssl_context')
+ if ssl_opts:
+ common_app_opts.update({'ssl_context': build_ssl_context()})
+ opts = get_options(sys.argv)
+ # Load secrets from SMS
+ sms.load_secrets()
+ if not opts.local and not opts.devtest: # normal deployment
+ app.run(port=internal_port, debug=False, **common_app_opts)
+ else:
+ port = internal_port if opts.local else external_port
+ app.run(port=port, debug=True, **common_app_opts)
+
+
+if __name__ == "__main__":
+ run_app()
diff --git a/osdf/config/__init__.py b/osdf/config/__init__.py
index 86156a1..e32d44e 100644
--- a/osdf/config/__init__.py
+++ b/osdf/config/__init__.py
@@ -27,6 +27,6 @@ class CoreConfig(metaclass=MetaSingleton):
def get_core_config(self, config_file=None):
if self.core_config is None:
- self.core_config = yaml.load(open(config_file))
+ self.core_config = yaml.safe_load(open(config_file))
return self.core_config
diff --git a/osdf/logging/osdf_logging.py b/osdf/logging/osdf_logging.py
index e457f18..a5a9739 100755
--- a/osdf/logging/osdf_logging.py
+++ b/osdf/logging/osdf_logging.py
@@ -191,6 +191,7 @@ class OOF_OSDFLogMessageFormatter(object):
@staticmethod
def received_http_response(resp):
+ """ """
return "Received response [code: {}, headers: {}, data: {}]".format(
resp.status_code, resp.headers, resp.__dict__)
diff --git a/osdf/models/api/pciOptimizationRequest.py b/osdf/models/api/pciOptimizationRequest.py
deleted file mode 100644
index f5ec6b7..0000000
--- a/osdf/models/api/pciOptimizationRequest.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-from schematics.types import BaseType, StringType, URLType, IntType
-from schematics.types.compound import ModelType, ListType, DictType
-
-from .common import OSDFModel
-
-
-class RequestInfo(OSDFModel):
- """Info for northbound request from client such as SO"""
- transactionId = StringType(required=True)
- requestId = StringType(required=True)
- callbackUrl = URLType(required=True)
- callbackHeader = DictType(BaseType)
- sourceId = StringType(required=True)
- requestType = StringType(required=True)
- numSolutions = IntType()
- optimizers = ListType(StringType(required=True))
- timeout = IntType()
-
-
-class ANRInfo(OSDFModel):
- cellId = StringType(required=True)
- removeableNeighbors = ListType(StringType())
-
-
-class CellInfo(OSDFModel):
- """Information specific to CellInfo """
- networkId = StringType(required=True)
- cellIdList = ListType(StringType(required=True))
- anrInputList = ListType(ModelType(ANRInfo))
- trigger = StringType()
-
-
-class PCIOptimizationAPI(OSDFModel):
- """Request for PCI optimization """
- requestInfo = ModelType(RequestInfo, required=True)
- cellInfo = ModelType(CellInfo, required=True)
diff --git a/osdf/models/api/pciOptimizationResponse.py b/osdf/models/api/pciOptimizationResponse.py
deleted file mode 100644
index 71d0986..0000000
--- a/osdf/models/api/pciOptimizationResponse.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-from schematics.types import StringType, IntType
-from schematics.types.compound import ModelType, ListType
-
-from .common import OSDFModel
-
-
-class PCISolution(OSDFModel):
- cellId = StringType(required=True)
- pci = IntType(required=True)
-
-
-class ANRSolution(OSDFModel):
- cellId = StringType(required=True)
- removeableNeighbors = ListType(StringType())
-
-
-class Solution(OSDFModel):
- networkId = StringType(required=True)
- pciSolutions = ListType(ListType(ModelType(PCISolution), min_size=1))
- anrSolutions = ListType(ListType(ModelType(ANRSolution), min_size=1))
-
-
-class PCIOptimizationResponse(OSDFModel):
- transactionId = StringType(required=True)
- requestId = StringType(required=True)
- requestStatus = StringType(required=True)
- statusMessage = StringType()
- solutions = ModelType(Solution, required=True)
diff --git a/osdf/models/api/placementRequest.py b/osdf/models/api/placementRequest.py
deleted file mode 100644
index a10ddc3..0000000
--- a/osdf/models/api/placementRequest.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# -------------------------------------------------------------------------
-# 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.
-#
-# -------------------------------------------------------------------------
-#
-
-from .common import OSDFModel
-from schematics.types import BaseType, StringType, URLType, IntType, BooleanType
-from schematics.types.compound import ModelType, ListType, DictType
-
-
-class RequestInfo(OSDFModel):
- """Info for northbound request from client such as SO"""
- transactionId = StringType(required=True)
- requestId = StringType(required=True)
- callbackUrl = URLType(required=True)
- callbackHeader = DictType(BaseType)
- sourceId = StringType(required=True)
- requestType = StringType(required=True)
- numSolutions = IntType()
- optimizers = ListType(StringType(required=True))
- timeout = IntType()
-
-
-class Candidates(OSDFModel):
- """Preferred candidate for a resource (sent as part of a request from client)"""
- identifierType = StringType(required=True)
- identifiers = ListType(StringType(required=True))
- cloudOwner = StringType()
-
-
-class ModelMetaData(OSDFModel):
- """Model information for a specific resource"""
- modelInvariantId = StringType(required=True)
- modelVersionId = StringType(required=True)
- modelName = StringType()
- modelType = StringType()
- modelVersion = StringType()
- modelCustomizationName = StringType()
-
-
-class LicenseModel(OSDFModel):
- entitlementPoolUUID = ListType(StringType(required=True))
- licenseKeyGroupUUID = ListType(StringType(required=True))
-
-
-class LicenseDemands(OSDFModel):
- resourceModuleName = StringType(required=True)
- serviceResourceId = StringType(required=True)
- resourceModelInfo = ModelType(ModelMetaData, required=True)
- existingLicenses = ModelType(LicenseModel)
-
-
-class LicenseInfo(OSDFModel):
- licenseDemands = ListType(ModelType(LicenseDemands))
-
-
-class PlacementDemand(OSDFModel):
- resourceModuleName = StringType(required=True)
- serviceResourceId = StringType(required=True)
- tenantId = StringType()
- resourceModelInfo = ModelType(ModelMetaData, required=True)
- existingCandidates = ListType(ModelType(Candidates))
- excludedCandidates = ListType(ModelType(Candidates))
- requiredCandidates = ListType(ModelType(Candidates))
-
-
-class ServiceInfo(OSDFModel):
- serviceInstanceId = StringType(required=True)
- modelInfo = ModelType(ModelMetaData, required=True)
- serviceName = StringType(required=True)
-
-
-class SubscriberInfo(OSDFModel):
- """Details on the customer that subscribes to the VNFs"""
- globalSubscriberId = StringType(required=True)
- subscriberName = StringType()
- subscriberCommonSiteId = StringType()
-
-
-class PlacementInfo(OSDFModel):
- """Information specific to placement optimization"""
- requestParameters = DictType(BaseType)
- placementDemands = ListType(ModelType(PlacementDemand), min_size=1)
- subscriberInfo = ModelType(SubscriberInfo)
-
-
-class PlacementAPI(OSDFModel):
- """Request for placement optimization (specific to optimization and additional metadata"""
- requestInfo = ModelType(RequestInfo, required=True)
- placementInfo = ModelType(PlacementInfo, required=True)
- licenseInfo = ModelType(LicenseInfo)
- serviceInfo = ModelType(ServiceInfo, required=True)
diff --git a/osdf/models/api/placementResponse.py b/osdf/models/api/placementResponse.py
deleted file mode 100644
index 063a9a8..0000000
--- a/osdf/models/api/placementResponse.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# -------------------------------------------------------------------------
-# 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.
-#
-# -------------------------------------------------------------------------
-#
-
-from .common import OSDFModel
-from schematics.types import BaseType, StringType
-from schematics.types.compound import ModelType, ListType, DictType
-
-
-# TODO: update osdf.models
-
-class LicenseSolution(OSDFModel):
- serviceResourceId = StringType(required=True)
- resourceModuleName = StringType(required=True)
- entitlementPoolUUID = ListType(StringType(required=True))
- licenseKeyGroupUUID = ListType(StringType(required=True))
- entitlementPoolInvariantUUID = ListType(StringType(required=True))
- licenseKeyGroupInvariantUUID = ListType(StringType(required=True))
-
-
-class Candidates(OSDFModel):
- """Preferred candidate for a resource (sent as part of a request from client)"""
- identifierType = StringType(required=True)
- identifiers = ListType(StringType(required=True))
- cloudOwner = StringType()
-
-
-class AssignmentInfo(OSDFModel):
- key = StringType(required=True)
- value = BaseType(required=True)
-
-
-class PlacementSolution(OSDFModel):
- serviceResourceId = StringType(required=True)
- resourceModuleName = StringType(required=True)
- solution = ModelType(Candidates, required=True)
- assignmentInfo = ListType(ModelType(AssignmentInfo))
-
-
-class Solution(OSDFModel):
- placementSolutions = ListType(ListType(ModelType(PlacementSolution), min_size=1))
- licenseSolutions = ListType(ModelType(LicenseSolution), min_size=1)
-
-
-class PlacementResponse(OSDFModel):
- transactionId = StringType(required=True)
- requestId = StringType(required=True)
- requestStatus = StringType(required=True)
- statusMessage = StringType()
- solutions = ModelType(Solution, required=True)
diff --git a/osdf/optimizers/licenseopt/simple_license_allocation.py b/osdf/optimizers/licenseopt/simple_license_allocation.py
deleted file mode 100644
index b2aaba4..0000000
--- a/osdf/optimizers/licenseopt/simple_license_allocation.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# -------------------------------------------------------------------------
-# 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.
-#
-# -------------------------------------------------------------------------
-#
-from osdf.utils.mdc_utils import mdc_from_json
-
-
-def license_optim(request_json):
- """
- Fetch license artifacts associated with the service model and search licensekey-group-UUID and entitlement-pool-uuid
- associated with the given att part number and nominal throughput in a request
- :param request_json: Request in a JSON format
- :return: A tuple of licensekey-group-uuid-list and entitlement-group-uuid-list
- """
- mdc_from_json(request_json)
- req_id = request_json["requestInfo"]["requestId"]
-
- model_name = request_json.get('placementInfo', {}).get('serviceInfo', {}).get('modelInfo', {}).get('modelName')
- service_name = model_name
-
- license_info = []
-
- for demand in request_json.get('placementInfo', {}).get('demandInfo', {}).get('licenseDemands', []):
- license_info.append(
- {'serviceResourceId': demand['serviceResourceId'],
- 'resourceModuleName': demand['resourceModuleName'],
- 'entitlementPoolList': "NOT SUPPORTED",
- 'licenseKeyGroupList': "NOT SUPPORTED"
- })
- return license_info
diff --git a/osdf/optimizers/pciopt/configdb.py b/osdf/optimizers/pciopt/configdb.py
deleted file mode 100644
index 8f003c2..0000000
--- a/osdf/optimizers/pciopt/configdb.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-from datetime import datetime as dt
-
-from osdf.logging.osdf_logging import debug_log
-from osdf.utils.interfaces import RestClient
-
-
-def request(req_object, osdf_config, flat_policies):
- """
- Process a configdb request from a Client (build Conductor API call, make the call, return result)
- :param req_object: Request parameters from the client
- :param osdf_config: Configuration specific to OSDF application (core + deployment)
- :param flat_policies: policies related to PCI Opt (fetched based on request)
- :return: response from ConfigDB (accounting for redirects from Conductor service
- """
- cell_list_response = {}
- config = osdf_config.deployment
- local_config = osdf_config.core
- uid, passwd = config['configDbUserName'], config['configDbPassword']
- req_id = req_object['requestInfo']['requestId']
- transaction_id = req_object['requestInfo']['transactionId']
- headers = dict(transaction_id=transaction_id)
-
- network_id = req_object['cellInfo']['networkId']
-
- cell_list_response['network_id'] = network_id
-
- ts = dt.strftime(dt.now(), '%Y-%m-%d %H:%M:%S%z')
-
- rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug, headers=headers)
-
- cell_list_url = '{}/{}/{}/{}'.format(config['configDbUrl'], config['configDbGetCellListUrl'], network_id, ts)
-
- cell_list_resp = rc.request(raw_response=True, url=cell_list_url)
- cell_resp = cell_list_resp.json()
-
- cell_list = []
- count = 0
- for cell_id in cell_resp:
- cell_info = {'cell_id': cell_id, 'id': count}
- nbr_list_url = '{}/{}/{}/{}'.format(config['configDbUrl'], config['configDbGetNbrListUrl'], cell_id, ts)
- nbr_list_raw = rc.request(url=nbr_list_url, raw_response=True)
- cell_info['nbr_list'] = get_neighbor_list(nbr_list_raw.json())
- cell_list.append(cell_info)
- count += 1
-
- cell_list_response['cell_list'] = cell_list
- return cell_resp, cell_list_response
-
-
-def get_neighbor_list(nbr_list_response):
- return nbr_list_response.get('nbrList', [])
diff --git a/osdf/optimizers/pciopt/pci_opt_processor.py b/osdf/optimizers/pciopt/pci_opt_processor.py
deleted file mode 100644
index 47c4288..0000000
--- a/osdf/optimizers/pciopt/pci_opt_processor.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-import traceback
-
-from requests import RequestException
-
-from osdf.logging.osdf_logging import metrics_log, MH, error_log
-from osdf.operation.error_handling import build_json_error_body
-from osdf.utils.interfaces import get_rest_client
-from .configdb import request as config_request
-from .solver.optimizer import pci_optimize as optimize
-from .solver.pci_utils import get_cell_id, get_pci_value
-from osdf.utils.mdc_utils import mdc_from_json
-
-"""
-This application generates PCI Optimization API calls using the information received from PCI-Handler-MS, SDN-C
-and Policy.
-"""
-
-
-def process_pci_optimation(request_json, osdf_config, flat_policies):
- """
- Process a PCI request from a Client (build config-db, policy and API call, make the call, return result)
- :param req_object: Request parameters from the client
- :param osdf_config: Configuration specific to OSDF application (core + deployment)
- :param flat_policies: policies related to pci (fetched based on request)
- :return: response from PCI Opt
- """
- try:
- mdc_from_json(request_json)
- rc = get_rest_client(request_json, service="pcih")
- req_id = request_json["requestInfo"]["requestId"]
- cell_info_list, network_cell_info = config_request(request_json, osdf_config, flat_policies)
- pci_response = get_solutions(cell_info_list, network_cell_info, request_json)
-
- metrics_log.info(MH.inside_worker_thread(req_id))
- except Exception as err:
- error_log.error("Error for {} {}".format(req_id, traceback.format_exc()))
-
- try:
- body = build_json_error_body(err)
- metrics_log.info(MH.sending_response(req_id, "ERROR"))
- rc.request(json=body, noresponse=True)
- except RequestException as err:
- MDC.put('requestID',req_id)
- error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
- raise err
-
-
- try:
- metrics_log.info(MH.calling_back_with_body(req_id, rc.url, pci_response))
- rc.request(json=pci_response, noresponse=True)
- except RequestException: # can't do much here but log it and move on
- error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
-
-
-def get_solutions(cell_info_list, network_cell_info, request_json):
- status, pci_solutions, anr_solutions = build_solution_list(cell_info_list, network_cell_info, request_json)
- return {
- "transactionId": request_json['requestInfo']['transactionId'],
- "requestId": request_json["requestInfo"]["requestId"],
- "requestStatus": "completed",
- "statusMessage": status,
- "solutions": {
- 'networkId': request_json['cellInfo']['networkId'],
- 'pciSolutions': pci_solutions,
- 'anrSolutions': anr_solutions
- }
- }
-
-
-def build_solution_list(cell_info_list, network_cell_info, request_json):
- status = "success"
- req_id = request_json["requestInfo"]["requestId"]
- try:
- opt_solution = optimize(network_cell_info, cell_info_list, request_json)
- pci_solutions = build_pci_solution(network_cell_info, opt_solution['pci'])
- anr_solutions = build_anr_solution(network_cell_info, opt_solution.get('removables', {}))
- except RuntimeError:
- error_log.error("Failed finding solution for {} {}".format(req_id, traceback.format_exc()))
- status = "failed"
- return status, pci_solutions, anr_solutions
-
-
-def build_pci_solution(network_cell_info, pci_solution):
- pci_solutions = []
- for k, v in pci_solution.items():
- old_pci = get_pci_value(network_cell_info, k)
- if old_pci != v:
- response = {
- 'cellId': get_cell_id(network_cell_info, k),
- 'pci': v
- }
- pci_solutions.append(response)
- return pci_solutions
-
-
-def build_anr_solution(network_cell_info, removables):
- anr_solutions = []
- for k, v in removables.items():
- response = {
- 'cellId': get_cell_id(network_cell_info, k),
- 'removeableNeighbors': list(map(lambda x: get_cell_id(network_cell_info, x), v))
- }
- anr_solutions.append(response)
- return anr_solutions
diff --git a/osdf/optimizers/pciopt/solver/__init__.py b/osdf/optimizers/pciopt/solver/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/osdf/optimizers/pciopt/solver/__init__.py
+++ /dev/null
diff --git a/osdf/optimizers/pciopt/solver/min_confusion.mzn b/osdf/optimizers/pciopt/solver/min_confusion.mzn
deleted file mode 100644
index ff56c18..0000000
--- a/osdf/optimizers/pciopt/solver/min_confusion.mzn
+++ /dev/null
@@ -1,98 +0,0 @@
-% -------------------------------------------------------------------------
-% Copyright (c) 2018 AT&T Intellectual Property
-%
-% Licensed under the Apache License, Version 2.0 (the "License");
-% you may not use this file except in compliance with the License.
-% You may obtain a copy of the License at
-%
-% http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS,
-% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-% See the License for the specific language governing permissions and
-% limitations under the License.
-%
-% -------------------------------------------------------------------------
-%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Parameters and its assertions
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Number of cells/radios.
-int: NUM_NODES;
-
-% Maximum number of Physical Cell Identifiers to be assigned to the nodes.
-int: NUM_PCIS;
-
-% Number of edges between neighbor nodes. There is a edge (i,j) if and only
-% if nodes i and j are neighbors, i.e., an user equipment (UE) can make
-% handoff between i and j. Such edges are used to avoid **COLLISION**, i.e.,
-% to guarantee that nodes i and j have different PCIs.
-int: NUM_NEIGHBORS;
-
-% Each line represents an edge between direct neighbors as defined before.
-array[1..NUM_NEIGHBORS, 1..2] of int: NEIGHBORS;
-
-% Number of undirect neighbor pairs (j, k) such that both j and k are direct
-% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
-% (i, k). Nodes (i, k) can generate "confunsions" in the network if they have
-% the same PCI. Such edges are used to avoid/minimize **CONFUSIONS**.
-int: NUM_SECOND_LEVEL_NEIGHBORS;
-
-% Each line represents an edge between undirect neighbors as defined before.
-array[1..NUM_SECOND_LEVEL_NEIGHBORS, 1..2] of int: SECOND_LEVEL_NEIGHBORS;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Decision variables
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Defines the PCI for each node.
-array[0..NUM_NODES-1] of var 0..NUM_PCIS-1: pci;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Constraints
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Direct neighbors must have different PCIs for avoid **COLLISION**.
-constraint
-forall(i in 1..NUM_NEIGHBORS)(
- pci[NEIGHBORS[i, 1]] != pci[NEIGHBORS[i, 2]]
-);
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Objective function
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Total number of confusions.
-var int: total_confusions =
- sum([bool2int(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] ==
- pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
- | i in 1..NUM_SECOND_LEVEL_NEIGHBORS]);
-
-% Minimize the total number of confusions.
-solve :: int_search(pci, smallest, indomain_min, complete)
-minimize total_confusions;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Output
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-output
-["PCI assigment"] ++
-["\nnode,pci"] ++
-[
- "\n" ++ show(node) ++ "," ++ show(pci[node])
-| node in 0..NUM_NODES-1
-] ++
-
-["\n\nConfusions"] ++
-["\nTotal confusions: " ++ show(total_confusions)] ++
-["\nConfusion pairs"] ++
-[
- "\n" ++ show(SECOND_LEVEL_NEIGHBORS[i, 1]) ++ "," ++
- show(SECOND_LEVEL_NEIGHBORS[i, 2])
-| i in 1..NUM_SECOND_LEVEL_NEIGHBORS where
- fix(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] == pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
-]
diff --git a/osdf/optimizers/pciopt/solver/min_confusion_inl.mzn b/osdf/optimizers/pciopt/solver/min_confusion_inl.mzn
deleted file mode 100644
index 0f0fc91..0000000
--- a/osdf/optimizers/pciopt/solver/min_confusion_inl.mzn
+++ /dev/null
@@ -1,140 +0,0 @@
-% -------------------------------------------------------------------------
-% Copyright (c) 2018 AT&T Intellectual Property
-%
-% Licensed under the Apache License, Version 2.0 (the "License");
-% you may not use this file except in compliance with the License.
-% You may obtain a copy of the License at
-%
-% http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS,
-% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-% See the License for the specific language governing permissions and
-% limitations under the License.
-%
-% -------------------------------------------------------------------------
-%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Parameters and its assertions
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Number of cells/radios.
-int: NUM_NODES;
-
-% Maximum number of Physical Cell Identifiers to be assigned to the nodes.
-int: NUM_PCIS;
-
-% Number of edges between neighbor nodes. There is a edge (i,j) if and only
-% if nodes i and j are neighbors, i.e., an user equipment (UE) can make
-% handoff between i and j. Such edges are used to avoid **COLLISION**, i.e.,
-% to guarantee that nodes i and j have different PCIs.
-int: NUM_NEIGHBORS;
-
-% Each line represents an edge between direct neighbors as defined before.
-array[1..NUM_NEIGHBORS, 1..2] of int: NEIGHBORS;
-
-% Number of undirect neighbor pairs (j, k) such that both j and k are direct
-% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
-% (i, k). Nodes (i, k) can generate "confunsions" in the network if they have
-% the same PCI. Such edges are used to avoid/minimize **CONFUSIONS**.
-int: NUM_SECOND_LEVEL_NEIGHBORS;
-
-% Each line represents an edge between undirect neighbors as defined before.
-array[1..NUM_SECOND_LEVEL_NEIGHBORS, 1..2] of int: SECOND_LEVEL_NEIGHBORS;
-
-% Number of ignorable neighbor links. Such links can be ignored during
-% optimization if needed.
-int: NUM_IGNORABLE_NEIGHBOR_LINKS;
-
-% The links that can be ignored if needed. Each line represents the two ends
-% of the links, like the previous structures.
-array[1..NUM_IGNORABLE_NEIGHBOR_LINKS, 1..2] of int: IGNORABLE_NEIGHBOR_LINKS;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Decision variables
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Defines the PCI for each node.
-array[0..NUM_NODES-1] of var 0..NUM_PCIS-1: pci;
-
-array[1..NUM_IGNORABLE_NEIGHBOR_LINKS] of var 0..1: used_ignorables;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Constraints
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Direct neighbors must have different PCIs for avoid **COLLISION**.
-% Forced links.
-constraint
-forall(i in 1..NUM_NEIGHBORS, j in 1..NUM_IGNORABLE_NEIGHBOR_LINKS
- where
- NEIGHBORS[i, 1] != IGNORABLE_NEIGHBOR_LINKS[j, 1] \/
- NEIGHBORS[i, 2] != IGNORABLE_NEIGHBOR_LINKS[j, 2]
-)(
- pci[NEIGHBORS[i, 1]] != pci[NEIGHBORS[i, 2]]
-);
-
-
-% Ignorable links.
-constraint
-forall(i in 1..NUM_NEIGHBORS, j in 1..NUM_IGNORABLE_NEIGHBOR_LINKS
- where
- NEIGHBORS[i, 1] == IGNORABLE_NEIGHBOR_LINKS[j, 1] /\
- NEIGHBORS[i, 2] == IGNORABLE_NEIGHBOR_LINKS[j, 2]
-)(
- used_ignorables[j] >= bool2int(pci[NEIGHBORS[i, 1]] == pci[NEIGHBORS[i, 2]])
-);
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Objective function
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Total number of confusions.
-var int: total_confusions =
- sum([bool2int(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] ==
- pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
- | i in 1..NUM_SECOND_LEVEL_NEIGHBORS]);
-
-% Total number of used ignorables links.
-var int: total_used_ignorables = sum(used_ignorables);
-
-solve :: int_search(pci, smallest, indomain_min, complete)
-
-% Minimize the total number of confusions.
-%minimize total_confusions;
-
-% Minimize the total number of confusions first,
-% then the number of used ignorables links.
-minimize (2 * NUM_IGNORABLE_NEIGHBOR_LINKS * total_confusions) +
- total_used_ignorables;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Output
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-output
-["PCI assigment"] ++
-["\nnode,pci"] ++
-[
- "\n" ++ show(node) ++ "," ++ show(pci[node])
-| node in 0..NUM_NODES-1
-] ++
-["\n\nTotal used ignorables links: " ++ show(total_used_ignorables)] ++
-["\nUsed ignorables links: "] ++
-[
- "\n" ++ show(IGNORABLE_NEIGHBOR_LINKS[i, 1]) ++
- "," ++ show(IGNORABLE_NEIGHBOR_LINKS[i, 2])
- | i in 1..NUM_IGNORABLE_NEIGHBOR_LINKS where fix(used_ignorables[i] > 0)
-] ++
-["\n\nConfusions"] ++
-["\nTotal confusions: " ++ show(total_confusions)] ++
-["\nConfusion pairs"] ++
-[
- "\n" ++ show(SECOND_LEVEL_NEIGHBORS[i, 1]) ++ "," ++
- show(SECOND_LEVEL_NEIGHBORS[i, 2])
- | i in 1..NUM_SECOND_LEVEL_NEIGHBORS where
- fix(pci[SECOND_LEVEL_NEIGHBORS[i, 1]] == pci[SECOND_LEVEL_NEIGHBORS[i, 2]])
-]
-
diff --git a/osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn b/osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn
deleted file mode 100644
index 0a9b3e3..0000000
--- a/osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn
+++ /dev/null
@@ -1,86 +0,0 @@
-% -------------------------------------------------------------------------
-% Copyright (c) 2018 AT&T Intellectual Property
-%
-% Licensed under the Apache License, Version 2.0 (the "License");
-% you may not use this file except in compliance with the License.
-% You may obtain a copy of the License at
-%
-% http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS,
-% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-% See the License for the specific language governing permissions and
-% limitations under the License.
-%
-% -------------------------------------------------------------------------
-%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Parameters and its assertions
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Number of cells/radios.
-int: NUM_NODES;
-
-% Maximum number of Physical Cell Identifiers to be assigned to the nodes.
-int: NUM_PCIS;
-
-% Number of edges between neighbor nodes. There is a edge (i,j) if and only
-% if nodes i and j are neighbors, i.e., an user equipment (UE) can make
-% handoff between i and j. Such edges are used to avoid **COLLISIONS**, i.e.,
-% to guarantee that nodes i and j have different PCIs.
-int: NUM_NEIGHBORS;
-
-% Each line represents an edge between direct neighbors as defined before.
-array[1..NUM_NEIGHBORS, 1..2] of int: NEIGHBORS;
-
-% Number of undirect neighbor pairs (j, k) such that both j and k are direct
-% neighbors of node i, i.e., (j, k) exits if and only if exists (i, j) and
-% (i, k). Nodes (i, k) can generate "confunsions" in the network if they have
-% the same PCI. Such edges are used to avoid/minimize **CONFUSIONS**.
-int: NUM_SECOND_LEVEL_NEIGHBORS;
-
-% Each line represents an edge between undirect neighbors as defined before.
-array[1..NUM_SECOND_LEVEL_NEIGHBORS, 1..2] of int: SECOND_LEVEL_NEIGHBORS;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Decision variables
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Defines the PCI for each node.
-array[0..NUM_NODES-1] of var 0..NUM_PCIS-1: pci;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Constraints
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Direct neighbors must have different PCIs for avoid **COLLISION**.
-constraint
-forall(i in 1..NUM_NEIGHBORS)(
- pci[NEIGHBORS[i, 1]] != pci[NEIGHBORS[i, 2]]
-);
-
-% Undirect neighbors must have different PCIs for avoid **CONFUSIONS**.
-constraint
-forall(i in 1..NUM_SECOND_LEVEL_NEIGHBORS)(
- pci[SECOND_LEVEL_NEIGHBORS[i, 1]] != pci[SECOND_LEVEL_NEIGHBORS[i, 2]]
-);
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Objective function
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% Just satisfy the problem.
-solve :: int_search(pci, smallest, indomain_min, complete) satisfy;
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Output
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-output
-["node,pci\n"] ++
-[
- show(node) ++ "," ++ show(pci[node]) ++ "\n"
-| node in 0..NUM_NODES-1
-]
diff --git a/osdf/optimizers/pciopt/solver/optimizer.py b/osdf/optimizers/pciopt/solver/optimizer.py
deleted file mode 100644
index 0a6d5a4..0000000
--- a/osdf/optimizers/pciopt/solver/optimizer.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-import itertools
-import os
-from collections import defaultdict
-
-import pymzn
-
-from .pci_utils import get_id
-
-BASE_DIR = os.path.dirname(__file__)
-
-
-def pci_optimize(network_cell_info, cell_info_list, request_json):
- neighbor_edges = get_neighbor_list(network_cell_info)
- second_level_edges = get_second_level_neighbor(network_cell_info)
- ignorable_links = get_ignorable_links(network_cell_info, request_json)
- anr_flag = is_anr(request_json)
-
- dzn_data = build_dzn_data(cell_info_list, ignorable_links, neighbor_edges, second_level_edges, anr_flag)
-
- return build_pci_solution(dzn_data, ignorable_links, anr_flag)
-
-
-def build_pci_solution(dzn_data, ignorable_links, anr_flag):
- mzn_solution = solve(get_mzn_model(anr_flag), dzn_data)
-
- solution = {'pci': mzn_solution[0]['pci']}
-
- if anr_flag:
- removables = defaultdict(list)
- used_ignorables = mzn_solution[0]['used_ignorables']
- index = 0
- for i in ignorable_links:
- if used_ignorables[index] > 0:
- removables[i[0]].append(i[1])
- index += 1
- solution['removables'] = removables
- return solution
-
-
-def build_dzn_data(cell_info_list, ignorable_links, neighbor_edges, second_level_edges, anr_flag):
- dzn_data = {
- 'NUM_NODES': len(cell_info_list),
- 'NUM_PCIS': len(cell_info_list),
- 'NUM_NEIGHBORS': len(neighbor_edges),
- 'NEIGHBORS': get_list(neighbor_edges),
- 'NUM_SECOND_LEVEL_NEIGHBORS': len(second_level_edges),
- 'SECOND_LEVEL_NEIGHBORS': get_list(second_level_edges)
- }
- if anr_flag:
- dzn_data['NUM_IGNORABLE_NEIGHBOR_LINKS'] = len(ignorable_links)
- dzn_data['IGNORABLE_NEIGHBOR_LINKS'] = get_list(ignorable_links)
- return dzn_data
-
-
-def get_mzn_model(anr_flag):
- if anr_flag:
- mzn_model = os.path.join(BASE_DIR, 'min_confusion_inl.mzn')
- else:
- mzn_model = os.path.join(BASE_DIR, 'no_conflicts_no_confusion.mzn')
- return mzn_model
-
-
-def is_anr(request_json):
- return 'pci-anr' in request_json["requestInfo"]["optimizers"]
-
-
-def get_list(edge_list):
- array_list = []
- for s in edge_list:
- array_list.append([s[0], s[1]])
- return sorted(array_list)
-
-
-def solve(mzn_model, dzn_data):
- return pymzn.minizinc(mzn=mzn_model, data=dzn_data)
-
-
-def get_neighbor_list(network_cell_info):
- neighbor_list = set()
- for cell in network_cell_info['cell_list']:
- add_to_neighbor_list(network_cell_info, cell, neighbor_list)
- return neighbor_list
-
-
-def add_to_neighbor_list(network_cell_info, cell, neighbor_list):
- for nbr in cell.get('nbr_list', []):
- host_id = cell['id']
- nbr_id = get_id(network_cell_info, nbr['targetCellId'])
- if nbr_id and host_id != nbr_id:
- neighbor_list.add((host_id, nbr_id))
-
-
-def get_second_level_neighbor(network_cell_info):
- second_neighbor_list = set()
- for cell in network_cell_info['cell_list']:
- comb_list = build_second_level_list(network_cell_info, cell)
- for comb in comb_list:
- if comb[0] and comb[1]:
- second_neighbor_list.add((comb[0], comb[1]))
- return sorted(second_neighbor_list)
-
-
-def build_second_level_list(network_cell_info, cell):
- second_nbr_list = []
- for nbr in cell.get('nbr_list', []):
- second_nbr_list.append(get_id(network_cell_info, nbr['targetCellId']))
- return [list(elem) for elem in list(itertools.combinations(second_nbr_list, 2))]
-
-
-def get_ignorable_links(network_cell_info, request_json):
- ignorable_list = set()
- anr_input_list = request_json["cellInfo"].get('anrInputList', [])
- if anr_input_list:
- for anr_info in anr_input_list:
- cell_id = get_id(network_cell_info, anr_info['cellId'])
- anr_removable = anr_info.get('removeableNeighbors', [])
- for anr in anr_removable:
- ignorable_list.add((cell_id, get_id(network_cell_info, anr)))
- return ignorable_list
diff --git a/osdf/optimizers/pciopt/solver/pci_utils.py b/osdf/optimizers/pciopt/solver/pci_utils.py
deleted file mode 100644
index 04829cf..0000000
--- a/osdf/optimizers/pciopt/solver/pci_utils.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-
-def get_id(network_cell_info, cell_id):
- for i in network_cell_info['cell_list']:
- if i['cell_id'] == cell_id:
- return i['id']
- return None
-
-
-def get_cell_id(network_cell_info, id):
- for i in network_cell_info['cell_list']:
- if i['id'] == id:
- return i['cell_id']
- return None
-
-
-def get_pci_value(network_cell_info, id):
- cell_id = get_cell_id(network_cell_info, id)
- for i in network_cell_info['cell_list']:
- for j in i['nbr_list']:
- if cell_id == j['targetCellId']:
- return j['pciValue']
- return None
diff --git a/osdf/optimizers/placementopt/conductor/__init__.py b/osdf/optimizers/placementopt/conductor/__init__.py
deleted file mode 100644
index 4b25e5b..0000000
--- a/osdf/optimizers/placementopt/conductor/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2017-2018 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
diff --git a/osdf/optimizers/placementopt/conductor/api_builder.py b/osdf/optimizers/placementopt/conductor/api_builder.py
deleted file mode 100644
index 08a7460..0000000
--- a/osdf/optimizers/placementopt/conductor/api_builder.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# -------------------------------------------------------------------------
-# 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.
-#
-# -------------------------------------------------------------------------
-#
-
-import json
-
-from jinja2 import Template
-
-import osdf.optimizers.placementopt.conductor.translation as tr
-from osdf.adapters.policy.utils import group_policies_gen
-from osdf.utils.programming_utils import list_flatten
-
-
-def _build_parameters(group_policies, request_json):
- """
- Function prepares parameters section for has request
- :param group_policies: filtered policies
- :param request_json: parameter data received from a client
- :return:
- """
- initial_params = tr.get_opt_query_data(request_json, group_policies['request_param_query'])
- params = dict()
- params.update({"REQUIRED_MEM": initial_params.pop("requiredMemory", "")})
- params.update({"REQUIRED_DISK": initial_params.pop("requiredDisk", "")})
- params.update({"customer_lat": initial_params.pop("customerLatitude", 0.0)})
- params.update({"customer_long": initial_params.pop("customerLongitude", 0.0)})
- params.update({"service_name": request_json['serviceInfo']['serviceName']})
- params.update({"service_id": request_json['serviceInfo']['serviceInstanceId']})
-
- for key, val in initial_params.items():
- if val and val != "":
- params.update({key: val})
-
- return params
-
-
-def conductor_api_builder(request_json, flat_policies: list, local_config,
- template="osdf/templates/conductor_interface.json"):
- """Build an OSDF southbound API call for HAS-Conductor/Placement optimization
- :param request_json: parameter data received from a client
- :param flat_policies: policy data received from the policy platform (flat policies)
- :param template: template to generate southbound API call to conductor
- :param local_config: local configuration file with pointers for the service specific information
- :param prov_status: provStatus retrieved from Subscriber policy
- :return: json to be sent to Conductor/placement optimization
- """
- templ = Template(open(template).read())
- gp = group_policies_gen(flat_policies, local_config)
- demand_vnf_name_list = []
-
- for placementDemand in request_json['placementInfo']['placementDemands']:
- demand_vnf_name_list.append(placementDemand['resourceModuleName'].lower())
- demand_list = tr.gen_demands(request_json, gp['vnfPolicy'])
- attribute_policy_list = tr.gen_attribute_policy(demand_vnf_name_list, gp['attribute'])
- distance_to_location_policy_list = tr.gen_distance_to_location_policy(
- demand_vnf_name_list, gp['distance_to_location'])
- inventory_policy_list = tr.gen_inventory_group_policy(demand_vnf_name_list, gp['inventory_group'])
- resource_instance_policy_list = tr.gen_resource_instance_policy(
- demand_vnf_name_list, gp['instance_fit'])
- resource_region_policy_list = tr.gen_resource_region_policy(demand_vnf_name_list, gp['region_fit'])
- zone_policy_list = tr.gen_zone_policy(demand_vnf_name_list, gp['zone'])
- optimization_policy_list = tr.gen_optimization_policy(demand_vnf_name_list, gp['placement_optimization'])
- reservation_policy_list = tr.gen_reservation_policy(demand_vnf_name_list, gp['instance_reservation'])
- capacity_policy_list = tr.gen_capacity_policy(demand_vnf_name_list, gp['vim_fit'])
- hpa_policy_list = tr.gen_hpa_policy(demand_vnf_name_list, gp['hpa'])
- req_params_dict = _build_parameters(gp, request_json)
- conductor_policies = [attribute_policy_list, distance_to_location_policy_list, inventory_policy_list,
- resource_instance_policy_list, resource_region_policy_list, zone_policy_list,
- reservation_policy_list, capacity_policy_list, hpa_policy_list]
- filtered_policies = [x for x in conductor_policies if len(x) > 0]
- policy_groups = list_flatten(filtered_policies)
- req_info = request_json['requestInfo']
- request_type = req_info.get('requestType', None)
- rendered_req = templ.render(
- requestType=request_type,
- demand_list=demand_list,
- policy_groups=policy_groups,
- optimization_policies=optimization_policy_list,
- name=req_info['requestId'],
- timeout=req_info['timeout'],
- limit=req_info['numSolutions'],
- request_params=req_params_dict,
- json=json)
- json_payload = json.dumps(json.loads(rendered_req)) # need this because template's JSON is ugly!
- return json_payload
diff --git a/osdf/optimizers/placementopt/conductor/conductor.py b/osdf/optimizers/placementopt/conductor/conductor.py
deleted file mode 100755
index 357efd1..0000000
--- a/osdf/optimizers/placementopt/conductor/conductor.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2015-2017 AT&T Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-"""
-This application generates conductor API calls using the information received from SO and Policy platform.
-"""
-
-import json
-import time
-
-from jinja2 import Template
-from requests import RequestException
-
-from osdf.logging.osdf_logging import debug_log
-from osdf.optimizers.placementopt.conductor.api_builder import conductor_api_builder
-from osdf.utils.interfaces import RestClient
-from osdf.operation.exceptions import BusinessException
-
-
-def request(req_object, osdf_config, flat_policies):
- """
- Process a placement request from a Client (build Conductor API call, make the call, return result)
- :param req_object: Request parameters from the client
- :param osdf_config: Configuration specific to SNIRO application (core + deployment)
- :param flat_policies: policies related to placement (fetched based on request)
- :param prov_status: provStatus retrieved from Subscriber policy
- :return: response from Conductor (accounting for redirects from Conductor service
- """
- config = osdf_config.deployment
- local_config = osdf_config.core
- uid, passwd = config['conductorUsername'], config['conductorPassword']
- conductor_url = config['conductorUrl']
- req_id = req_object['requestInfo']['requestId']
- transaction_id = req_object['requestInfo']['transactionId']
- headers = dict(transaction_id=transaction_id)
- placement_ver_enabled = config.get('placementVersioningEnabled', False)
-
- if placement_ver_enabled:
- cond_minor_version = config.get('conductorMinorVersion', None)
- if cond_minor_version is not None:
- x_minor_version = str(cond_minor_version)
- headers.update({'X-MinorVersion': x_minor_version})
- debug_log.debug("Versions set in HTTP header to conductor: X-MinorVersion: {} ".format(x_minor_version))
-
- max_retries = config.get('conductorMaxRetries', 30)
- ping_wait_time = config.get('conductorPingWaitTime', 60)
-
- rc = RestClient(userid=uid, passwd=passwd, method="GET", log_func=debug_log.debug, headers=headers)
- conductor_req_json_str = conductor_api_builder(req_object, flat_policies, local_config)
- conductor_req_json = json.loads(conductor_req_json_str)
-
- debug_log.debug("Sending first Conductor request for request_id {}".format(req_id))
- resp, raw_resp = initial_request_to_conductor(rc, conductor_url, conductor_req_json)
- # Very crude way of keeping track of time.
- # We are not counting initial request time, first call back, or time for HTTP request
- total_time, ctr = 0, 2
- client_timeout = req_object['requestInfo']['timeout']
- configured_timeout = max_retries * ping_wait_time
- max_timeout = min(client_timeout, configured_timeout)
-
- while True: # keep requesting conductor till we get a result or we run out of time
- if resp is not None:
- if resp["plans"][0].get("status") in ["error"]:
- raise RequestException(response=raw_resp, request=raw_resp.request)
-
- if resp["plans"][0].get("status") in ["done", "not found"]:
- if resp["plans"][0].get("recommendations"):
- return conductor_response_processor(resp, raw_resp, req_id)
- else: # "solved" but no solutions found
- return conductor_no_solution_processor(resp, raw_resp, req_id)
- new_url = resp['plans'][0]['links'][0][0]['href'] # TODO: check why a list of lists
-
- if total_time >= max_timeout:
- raise BusinessException("Conductor could not provide a solution within {} seconds,"
- "this transaction is timing out".format(max_timeout))
- time.sleep(ping_wait_time)
- ctr += 1
- debug_log.debug("Attempt number {} url {}; prior status={}".format(ctr, new_url, resp['plans'][0]['status']))
- total_time += ping_wait_time
-
- try:
- raw_resp = rc.request(new_url, raw_response=True)
- resp = raw_resp.json()
- except RequestException as e:
- debug_log.debug("Conductor attempt {} for request_id {} has failed because {}".format(ctr, req_id, str(e)))
-
-
-def initial_request_to_conductor(rc, conductor_url, conductor_req_json):
- """First steps in the request-redirect chain in making a call to Conductor
- :param rc: REST client object for calling conductor
- :param conductor_url: conductor's base URL to submit a placement request
- :param conductor_req_json: request json object to send to Conductor
- :return: URL to check for follow up (similar to redirects); we keep checking these till we get a result/error
- """
- debug_log.debug("Payload to Conductor: {}".format(json.dumps(conductor_req_json)))
- raw_resp = rc.request(url=conductor_url, raw_response=True, method="POST", json=conductor_req_json)
- resp = raw_resp.json()
- if resp["status"] != "template":
- raise RequestException(response=raw_resp, request=raw_resp.request)
- time.sleep(10) # 10 seconds wait time to avoid being too quick!
- plan_url = resp["links"][0][0]["href"]
- debug_log.debug("Attempting to read the plan from the conductor provided url {}".format(plan_url))
- raw_resp = rc.request(raw_response=True, url=plan_url) # TODO: check why a list of lists for links
- resp = raw_resp.json()
-
- if resp["plans"][0]["status"] in ["error"]:
- raise RequestException(response=raw_resp, request=raw_resp.request)
- return resp, raw_resp # now the caller of this will handle further follow-ups
-
-
-def conductor_response_processor(conductor_response, raw_response, req_id):
- """Build a response object to be sent to client's callback URL from Conductor's response
- This includes Conductor's placement optimization response, and required ASDC license artifacts
-
- :param conductor_response: JSON response from Conductor
- :param raw_response: Raw HTTP response corresponding to above
- :param req_id: Id of a request
- :return: JSON object that can be sent to the client's callback URL
- """
- composite_solutions = []
- name_map = {"physical-location-id": "cloudClli", "host_id": "vnfHostName",
- "cloud_version": "cloudVersion", "cloud_owner": "cloudOwner",
- "cloud": "cloudRegionId", "service": "serviceInstanceId", "is_rehome": "isRehome",
- "location_id": "locationId", "location_type": "locationType", "directives": "oof_directives"}
- for reco in conductor_response['plans'][0]['recommendations']:
- for resource in reco.keys():
- c = reco[resource]['candidate']
- solution = {
- 'resourceModuleName': resource,
- 'serviceResourceId': reco[resource].get('service_resource_id', ""),
- 'solution': {"identifierType": name_map.get(c['inventory_type'], c['inventory_type']),
- 'identifiers': [c['candidate_id']],
- 'cloudOwner': c.get('cloud_owner', "")},
- 'assignmentInfo': []
- }
- for key, value in c.items():
- if key in ["location_id", "location_type", "is_rehome", "host_id"]:
- try:
- solution['assignmentInfo'].append({"key": name_map.get(key, key), "value": value})
- except KeyError:
- debug_log.debug("The key[{}] is not mapped and will not be returned in assignment info".format(key))
-
- for key, value in reco[resource]['attributes'].items():
- try:
- solution['assignmentInfo'].append({"key": name_map.get(key, key), "value": value})
- except KeyError:
- debug_log.debug("The key[{}] is not mapped and will not be returned in assignment info".format(key))
- composite_solutions.append(solution)
-
- request_status = "completed" if conductor_response['plans'][0]['status'] == "done" \
- else conductor_response['plans'][0]['status']
- transaction_id = raw_response.headers.get('transaction_id', "")
- status_message = conductor_response.get('plans')[0].get('message', "")
-
- solution_info = {}
- if composite_solutions:
- solution_info.setdefault('placementSolutions', [])
- solution_info['placementSolutions'].append(composite_solutions)
-
- resp = {
- "transactionId": transaction_id,
- "requestId": req_id,
- "requestStatus": request_status,
- "statusMessage": status_message,
- "solutions": solution_info
- }
- return resp
-
-
-def conductor_no_solution_processor(conductor_response, raw_response, request_id,
- template_placement_response="templates/plc_opt_response.jsont"):
- """Build a response object to be sent to client's callback URL from Conductor's response
- This is for case where no solution is found
-
- :param conductor_response: JSON response from Conductor
- :param raw_response: Raw HTTP response corresponding to above
- :param request_id: request Id associated with the client request (same as conductor response's "name")
- :param template_placement_response: the template for generating response to client (plc_opt_response.jsont)
- :return: JSON object that can be sent to the client's callback URL
- """
- status_message = conductor_response["plans"][0].get("message")
- templ = Template(open(template_placement_response).read())
- return json.loads(templ.render(composite_solutions=[], requestId=request_id, license_solutions=[],
- transactionId=raw_response.headers.get('transaction_id', ""),
- requestStatus="completed", statusMessage=status_message, json=json))
-
-
diff --git a/osdf/optimizers/placementopt/conductor/remote_opt_processor.py b/osdf/optimizers/placementopt/conductor/remote_opt_processor.py
deleted file mode 100644
index 22a0307..0000000
--- a/osdf/optimizers/placementopt/conductor/remote_opt_processor.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# -------------------------------------------------------------------------
-# 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.
-#
-# -------------------------------------------------------------------------
-#
-
-from requests import RequestException
-
-import traceback
-from osdf.operation.error_handling import build_json_error_body
-from osdf.logging.osdf_logging import metrics_log, MH, error_log
-from osdf.optimizers.placementopt.conductor import conductor
-from osdf.optimizers.licenseopt.simple_license_allocation import license_optim
-from osdf.utils.interfaces import get_rest_client
-from osdf.utils.mdc_utils import mdc_from_json
-
-
-def process_placement_opt(request_json, policies, osdf_config):
- """Perform the work for placement optimization (e.g. call SDC artifact and make conductor request)
- NOTE: there is scope to make the requests to policy asynchronous to speed up overall performance
- :param request_json: json content from original request
- :param policies: flattened policies corresponding to this request
- :param osdf_config: configuration specific to OSDF app
- :param prov_status: provStatus retrieved from Subscriber policy
- :return: None, but make a POST to callback URL
- """
-
- try:
- mdc_from_json(request_json)
- rc = get_rest_client(request_json, service="so")
- req_id = request_json["requestInfo"]["requestId"]
- transaction_id = request_json['requestInfo']['transactionId']
-
- metrics_log.info(MH.inside_worker_thread(req_id))
- license_info = None
- if request_json.get('licenseInfo', {}).get('licenseDemands'):
- license_info = license_optim(request_json)
-
- # Conductor only handles placement, only call Conductor if placementDemands exist
- if request_json.get('placementInfo', {}).get('placementDemands'):
- metrics_log.info(MH.requesting("placement/conductor", req_id))
- placement_response = conductor.request(request_json, osdf_config, policies)
- if license_info: # Attach license solution if it exists
- placement_response['solutionInfo']['licenseInfo'] = license_info
- else: # License selection only scenario
- placement_response = {
- "transactionId": transaction_id,
- "requestId": req_id,
- "requestStatus": "completed",
- "statusMessage": "License selection completed successfully",
- "solutionInfo": {"licenseInfo": license_info}
- }
- except Exception as err:
- error_log.error("Error for {} {}".format(req_id, traceback.format_exc()))
-
- try:
- body = build_json_error_body(err)
- metrics_log.info(MH.sending_response(req_id, "ERROR"))
- rc.request(json=body, noresponse=True)
- except RequestException:
- error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
- return
-
- try:
- metrics_log.info(MH.calling_back_with_body(req_id, rc.url,placement_response))
- rc.request(json=placement_response, noresponse=True)
- except RequestException : # can't do much here but log it and move on
- error_log.error("Error sending asynchronous notification for {} {}".format(req_id, traceback.format_exc()))
-
diff --git a/osdf/optimizers/placementopt/conductor/translation.py b/osdf/optimizers/placementopt/conductor/translation.py
deleted file mode 100644
index 046e6e8..0000000
--- a/osdf/optimizers/placementopt/conductor/translation.py
+++ /dev/null
@@ -1,283 +0,0 @@
-# -------------------------------------------------------------------------
-# 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.
-#
-# -------------------------------------------------------------------------
-#
-import copy
-import json
-import yaml
-import re
-
-from osdf.utils.data_conversion import text_to_symbol
-from osdf.utils.programming_utils import dot_notation
-
-policy_config_mapping = yaml.load(open('config/has_config.yaml')).get('policy_config_mapping')
-
-
-def get_opt_query_data(req_json, policies):
- """
- Fetch service and order specific details from the requestParameters field of a request.
- :param req_json: a request file
- :param policies: A set of policies
- :return: A dictionary with service and order-specific attributes.
- """
- req_param_dict = {}
- if 'requestParameters' in req_json["placementInfo"]:
- req_params = req_json["placementInfo"]["requestParameters"]
- for policy in policies:
- for queryProp in policy['content']['queryProperties']:
- attr_val = queryProp['value'] if 'value' in queryProp and queryProp['value'] != "" \
- else dot_notation(req_params, queryProp['attribute_location'])
- if attr_val is not None:
- req_param_dict.update({queryProp['attribute']: attr_val})
- return req_param_dict
-
-
-def gen_optimization_policy(vnf_list, optimization_policy):
- """Generate optimization policy details to pass to Conductor
- :param vnf_list: List of vnf's to used in placement request
- :param optimization_policy: optimization objective policy information provided in the incoming request
- :return: List of optimization objective policies in a format required by Conductor
- """
- optimization_policy_list = []
- for policy in optimization_policy:
- content = policy['content']
- parameter_list = []
- parameters = ["cloud_version", "hpa_score"]
-
- for attr in content['objectiveParameter']['parameterAttributes']:
- parameter = attr['parameter'] if attr['parameter'] in parameters else attr['parameter']+"_between"
- vnfs = get_matching_vnfs(attr['resources'], vnf_list)
- for vnf in vnfs:
- value = [vnf] if attr['parameter'] in parameters else [attr['customerLocationInfo'], vnf]
- parameter_list.append({
- attr['operator']: [attr['weight'], {parameter: value}]
- })
-
- optimization_policy_list.append({
- content['objective']: {content['objectiveParameter']['operator']: parameter_list }
- })
- return optimization_policy_list
-
-
-def get_matching_vnfs(resources, vnf_list, match_type="intersection"):
- """Get a list of matching VNFs from the list of resources
- :param resources:
- :param vnf_list: List of vnfs to used in placement request
- :param match_type: "intersection" or "all" or "any" (any => send all_vnfs if there is any intersection)
- :return: List of matching VNFs
- """
- resources_lcase = [x.lower() for x in resources]
- if match_type == "all": # don't bother with any comparisons
- return resources if set(resources_lcase) <= set(vnf_list) else None
- common_vnfs = set(vnf_list) & set(resources_lcase)
- common_resources = [x for x in resources if x.lower() in common_vnfs]
- if match_type == "intersection": # specifically requested intersection
- return list(common_resources)
- return resources if common_vnfs else None # "any" match => all resources to be returned
-
-
-def gen_policy_instance(vnf_list, resource_policy, match_type="intersection", rtype=None):
- """Generate a list of policies
- :param vnf_list: List of vnf's to used in placement request
- :param resource_policy: policy for this specific resource
- :param match_type: How to match the vnf_names with the vnf_list (intersection or "any")
- intersection => return intersection; "any" implies return all vnf_names if intersection is not null
- :param rtype: resource type (e.g. resourceRegionProperty or resourceInstanceProperty)
- None => no controller information added to the policy specification to Conductor
- :return: resource policy list in a format required by Conductor
- """
- resource_policy_list = []
- related_policies = []
- for policy in resource_policy:
- pc = policy['content']
- demands = get_matching_vnfs(pc['resources'], vnf_list, match_type=match_type)
- resource = {pc['identity']: {'type': pc['policyType'], 'demands': demands}}
-
- if rtype:
- resource[pc['identity']]['properties'] = {'controller': pc[rtype]['controller'],
- 'request': json.loads(pc[rtype]['request'])}
- if demands and len(demands) != 0:
- resource_policy_list.append(resource)
- related_policies.append(policy)
- return resource_policy_list, related_policies
-
-
-def gen_resource_instance_policy(vnf_list, resource_instance_policy):
- """Get policies governing resource instances in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, resource_instance_policy, rtype='resourceInstanceProperty')
- return cur_policies
-
-
-def gen_resource_region_policy(vnf_list, resource_region_policy):
- """Get policies governing resource region in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, resource_region_policy, rtype='resourceRegionProperty')
- return cur_policies
-
-
-def gen_inventory_group_policy(vnf_list, inventory_group_policy):
- """Get policies governing inventory group in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, inventory_group_policy, rtype=None)
- return cur_policies
-
-
-def gen_reservation_policy(vnf_list, reservation_policy):
- """Get policies governing resource instances in order to populate the Conductor API call"""
- cur_policies, _ = gen_policy_instance(vnf_list, reservation_policy, rtype='instanceReservationProperty')
- return cur_policies
-
-
-def gen_distance_to_location_policy(vnf_list, distance_to_location_policy):
- """Get policies governing distance-to-location for VNFs in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, distance_to_location_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- properties = p_main['content']['distanceProperties']
- pcp_d = properties['distance']
- p_new[p_main['content']['identity']]['properties'] = {
- 'distance': pcp_d['operator'] + " " + pcp_d['value'].lower() + " " + pcp_d['unit'].lower(),
- 'location': properties['locationInfo']
- }
- return cur_policies
-
-
-def gen_attribute_policy(vnf_list, attribute_policy):
- """Get policies governing attributes of VNFs in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, attribute_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- properties = p_main['content']['cloudAttributeProperty']
- attribute_mapping = policy_config_mapping['attributes'] # wanted attributes and mapping
- p_new[p_main['content']['identity']]['properties'] = {
- 'evaluate': dict((k, properties.get(attribute_mapping.get(k))) for k in attribute_mapping.keys())
- }
- return cur_policies # cur_policies gets updated in place...
-
-
-def gen_zone_policy(vnf_list, zone_policy):
- """Get zone policies in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, zone_policy, match_type="all", rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- pmz = p_main['content']['affinityProperty']
- p_new[p_main['content']['identity']]['properties'] = {'category': pmz['category'], 'qualifier': pmz['qualifier']}
- return cur_policies
-
-
-def gen_capacity_policy(vnf_list, capacity_policy):
- """Get zone policies in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, capacity_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- pmz = p_main['content']['capacityProperty']
- p_new[p_main['content']['identity']]['properties'] = \
- {"controller": pmz['controller'], 'request': json.loads(pmz['request'])}
- return cur_policies
-
-
-def gen_hpa_policy(vnf_list, hpa_policy):
- """Get zone policies in order to populate the Conductor API call"""
- cur_policies, related_policies = gen_policy_instance(vnf_list, hpa_policy, rtype=None)
- for p_new, p_main in zip(cur_policies, related_policies): # add additional fields to each policy
- p_new[p_main['content']['identity']]['properties'] = {'evaluate': p_main['content']['flavorFeatures']}
- return cur_policies
-
-
-def get_augmented_policy_attributes(policy_property, demand):
- """Get policy attributes and augment them using policy_config_mapping and demand information"""
- attributes = copy.copy(policy_property['attributes'])
- remapping = policy_config_mapping['remapping']
- extra = dict((x, demand['resourceModelInfo'][remapping[x]]) for x in attributes if x in remapping)
- attributes.update(extra)
- return attributes
-
-
-def get_candidates_demands(demand):
- """Get demands related to candidates; e.g. excluded/required"""
- res = {}
- for k, v in policy_config_mapping['candidates'].items():
- if k not in demand:
- continue
- res[v] = [{'inventory_type': x['identifierType'], 'candidate_id': x['identifiers']} for x in demand[k]]
- return res
-
-
-def get_policy_properties(demand, policies):
- """Get policy_properties for cases where there is a match with the demand"""
- for policy in policies:
- policy_demands = set([x.lower() for x in policy['content'].get('resources', [])])
- if demand['resourceModuleName'].lower() not in policy_demands:
- continue # no match for this policy
- for policy_property in policy['content']['vnfProperties']:
- yield policy_property
-
-
-def get_demand_properties(demand, policies):
- """Get list demand properties objects (named tuples) from policy"""
- demand_properties = []
- for policy_property in get_policy_properties(demand, policies):
- prop = dict(inventory_provider=policy_property['inventoryProvider'],
- inventory_type=policy_property['inventoryType'],
- service_type=demand['serviceResourceId'],
- service_resource_id=demand['serviceResourceId'])
-
- prop.update({'unique': policy_property['unique']} if 'unique' in policy_property and
- policy_property['unique'] else {})
- prop['attributes'] = dict()
- prop['attributes'].update({'global-customer-id': policy_property['customerId']}
- if policy_property['customerId'] else {})
- prop['attributes'].update({'model-invariant-id': demand['resourceModelInfo']['modelInvariantId']}
- if demand['resourceModelInfo']['modelInvariantId'] else {})
- prop['attributes'].update({'model-version-id': demand['resourceModelInfo']['modelVersionId']}
- if demand['resourceModelInfo']['modelVersionId'] else {})
- prop['attributes'].update({'equipment-role': policy_property['equipmentRole']}
- if policy_property['equipmentRole'] else {})
-
- if policy_property.get('attributes'):
- for attr_key, attr_val in policy_property['attributes'].items():
- update_converted_attribute(attr_key, attr_val, prop)
-
- prop.update(get_candidates_demands(demand))
- demand_properties.append(prop)
- return demand_properties
-
-
-def update_converted_attribute(attr_key, attr_val, properties):
- """
- Updates dictonary of attributes with one specified in the arguments.
- Automatically translates key namr from camelCase to hyphens
- :param attr_key: key of the attribute
- :param attr_val: value of the attribute
- :param properties: dictionary with attributes to update
- :return:
- """
- if attr_val:
- remapping = policy_config_mapping['attributes']
- if remapping.get(attr_key):
- key_value = remapping.get(attr_key)
- else:
- key_value = re.sub('(.)([A-Z][a-z]+)', r'\1-\2', attr_key)
- key_value = re.sub('([a-z0-9])([A-Z])', r'\1-\2', key_value).lower()
- properties['attributes'].update({key_value: attr_val})
-
-
-def gen_demands(req_json, vnf_policies):
- """Generate list of demands based on request and VNF policies
- :param req_json: Request object from the client (e.g. MSO)
- :param vnf_policies: Policies associated with demand resources (e.g. from grouped_policies['vnfPolicy'])
- :return: list of demand parameters to populate the Conductor API call
- """
- demand_dictionary = {}
- for demand in req_json['placementInfo']['placementDemands']:
- prop = get_demand_properties(demand, vnf_policies)
- if len(prop) > 0:
- demand_dictionary.update({demand['resourceModuleName']: prop})
- return demand_dictionary
diff --git a/osdf/optimizers/routeopt/simple_route_opt.py b/osdf/optimizers/routeopt/simple_route_opt.py
deleted file mode 100644
index b00180d..0000000
--- a/osdf/optimizers/routeopt/simple_route_opt.py
+++ /dev/null
@@ -1,153 +0,0 @@
-# -------------------------------------------------------------------------
-# Copyright (c) 2018 Huawei Intellectual Property
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# -------------------------------------------------------------------------
-#
-
-import requests
-from requests.auth import HTTPBasicAuth
-
-from osdf.utils.mdc_utils import mdc_from_json
-
-
-class RouteOpt:
-
- """
- This values will need to deleted..
- only added for the debug purpose
- """
- # DNS server and standard port of AAI..
- # TODO: read the port from the configuration and add to DNS
- aai_host = "https://aai.api.simpledemo.onap.org:8443"
- aai_headers = {
- "X-TransactionId": "9999",
- "X-FromAppId": "OOF",
- "Accept": "application/json",
- "Content-Type": "application/json",
- "Real-Time": "true"
- }
-
- def isCrossONAPLink(self, logical_link):
- """
- This method checks if cross link is cross onap
- :param logical_link:
- :return:
- """
- for relationship in logical_link["relationship-list"]["relationship"]:
- if relationship["related-to"] == "ext-aai-network":
- return True
- return False
-
- def getRoute(self, request):
- """
- This method checks
- :param logical_link:
- :return:
- """
- mdc_from_json(request)
-
- src_access_node_id = request["srcPort"]["src-access-node-id"]
- dst_access_node_id = request["dstPort"]["dst-access-node-id"]
-
-
- ingress_p_interface = None
- egress_p_interface = None
-
- # for the case of request_json for same domain, return the same node with destination update
- if src_access_node_id == dst_access_node_id:
- data = '{'\
- '"vpns":['\
- '{'\
- '"access-topology-id": "' + request["srcPort"]["src-access-topology-id"] + '",'\
- '"access-client-id": "' + request["srcPort"]["src-access-client-id"] + '",'\
- '"access-provider-id": "' + request["srcPort"]["src-access-provider-id"]+ '",'\
- '"access-node-id": "' + request["srcPort"]["src-access-node-id"]+ '",'\
- '"src-access-ltp-id": "' + request["srcPort"]["src-access-ltp-id"]+ '",'\
- '"dst-access-ltp-id": "' + request["dstPort"]["dst-access-ltp-id"] +'"'\
- '}'\
- ']'\
- '}'
- return data
- else:
- logical_links = self.get_logical_links()
-
- # take the logical link where both the p-interface in same onap
- if logical_links != None:
- for logical_link in logical_links.get("logical-link"):
- if not self.isCrossONAPLink(logical_link):
- # link is in local ONAP
- for relationship in logical_link["relationship-list"]["relationship"]:
- if relationship["related-to"] == "p-interface":
- if src_access_node_id in relationship["related-link"]:
- i_interface = relationship["related-link"].split("/")[-1]
- ingress_p_interface = i_interface.split("-")[-1]
- if dst_access_node_id in relationship["related-link"]:
- e_interface = relationship["related-link"].split("/")[-1]
- egress_p_interface = e_interface.split("-")[-1]
- data = '{'\
- '"vpns":['\
- '{'\
- '"access-topology-id": "' + request["srcPort"]["src-access-topology-id"] + '",'\
- '"access-client-id": "' + request["srcPort"]["src-access-client-id"] + '",'\
- '"access-provider-id": "' + request["srcPort"]["src-access-provider-id"]+ '",'\
- '"access-node-id": "' + request["srcPort"]["src-access-node-id"]+ '",'\
- '"src-access-ltp-id": "' + request["srcPort"]["src-access-ltp-id"]+ '",'\
- '"dst-access-ltp-id": "' + ingress_p_interface +'"'\
- '},'\
- '{' \
- '"access-topology-id": "' + request["dstPort"]["dst-access-topology-id"] + '",' \
- '"access-topology-id": "' + request["dstPort"]["dst-access-topology-id"]+ '",' \
- '"access-provider-id": "' + request["dstPort"]["dst-access-provider-id"]+ '",' \
- '"access-node-id": "' + request["dstPort"]["dst-access-node-id"]+ '",' \
- '"src-access-ltp-id": "' + egress_p_interface + '",' \
- '"dst-access-ltp-id": "' + request["dstPort"]["dst-access-ltp-id"] + '"' \
- '}'\
- ']'\
- '}'
- return data
-
-
- def get_pinterface(self, url):
- """
- This method returns details for p interface
- :return: details of p interface
- """
- aai_req_url = self.aai_host + url
- response = requests.get(aai_req_url,
- headers=self.aai_headers,
- auth=HTTPBasicAuth("AAI", "AAI"),
- verify=False)
-
- if response.status_code == 200:
- return response.json()
-
-
- def get_logical_links(self):
- """
- This method returns list of all cross ONAP links
- from /aai/v14/network/logical-links?operation-status="Up"
- :return: logical-links[]
- """
- logical_link_url = "/aai/v13/network/logical-links?operational-status=up"
- aai_req_url = self.aai_host + logical_link_url
-
- response = requests.get(aai_req_url,
- headers=self.aai_headers,
- auth=HTTPBasicAuth("AAI", "AAI"),
- verify=False)
-
- logical_links = None
- if response.status_code == 200:
- return response.json() \ No newline at end of file
diff --git a/osdf/templates/cms_opt_request.jsont b/osdf/templates/cms_opt_request.jsont
deleted file mode 100755
index 006562b..0000000
--- a/osdf/templates/cms_opt_request.jsont
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "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
deleted file mode 100755
index 75ecbe5..0000000
--- a/osdf/templates/cms_opt_request.jsont_1707_v1
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "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
deleted file mode 100755
index bcafa45..0000000
--- a/osdf/templates/cms_opt_request_1702.jsont
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "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
deleted file mode 100644
index a8817df..0000000
--- a/osdf/templates/cms_opt_response.jsont
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "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
deleted file mode 100755
index 030d6a0..0000000
--- a/osdf/templates/conductor_interface.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "name": "{{ name }}",
- "files": {},
- "timeout": {{ timeout }},
- "num_solution": "{{ limit }}",
- "template": {
- "homing_template_version": "2017-10-10",
- "parameters": {
- {% set comma=joiner(",") %}
- {% for key, value in request_params.items() %} {{ comma() }}
- "{{key}}": {{ json.dumps(value) }}
- {% endfor %}
- },
- "locations": {
- "customer_loc": {
- "latitude": { "get_param": "customer_lat" },
- "longitude": { "get_param": "customer_long" }
- }
- },
- "demands": {{ json.dumps(demand_list) }},
- {% set comma_main = joiner(",") %}
- "constraints": {
- {% set comma=joiner(",") %}
- {% for elem in policy_groups %} {{ comma() }}
- {% for key, value in elem.items() %}
- "{{key}}": {{ json.dumps(value) }}
- {% endfor %}
- {% endfor %}
- },
- "optimization": {
- {% set comma=joiner(",") %}
- {% for elem in optimization_policies %} {{ comma() }}
- {% for key, value in elem.items() %}
- "{{key}}": {{ json.dumps(value) }}
- {% endfor %}
- {% endfor %}
- }
- }
-}
diff --git a/osdf/templates/license_opt_request.jsont b/osdf/templates/license_opt_request.jsont
deleted file mode 100644
index 7baa759..0000000
--- a/osdf/templates/license_opt_request.jsont
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "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
deleted file mode 100755
index a218b8a..0000000
--- a/osdf/templates/plc_opt_request.jsont
+++ /dev/null
@@ -1,142 +0,0 @@
-{
- "name": "{{ name }}",
- "files": "{{ files }}",
- "timeout": "{{ timeout }}",
- "num_solution": "{{ limit }}",
- "template": {
- "CUST_ID": "{{ cust_id }}",
- "E2EVPNKEY": "{{ e2evpnkey }}",
- "UCPEHOST": "{{ ucpehost }}",
- "WAN_PORT1_UP": "{{ wan_port1_up }}",
- "WAN_PORT1_DOWN": "{{ wan_port1_down }}",
- "EFFECTIVE_BANDWIDTH": "{{ effective_bandwidth }}",
- "SERVICE_INST": "{{ service_inst }}",
- "locations": {
- "customer_loc": {
- "host_name": "{{ ucpehost }}"
- }
- },
- "demands": [
- {% set comma=joiner(",") %}
- {% for demand in demand_list %} {{ comma() }}
- {
- "{{ demand.vnf_name }}": [
- {% set comma2=joiner(",") %}
- {% for property in demand.property %}
- "inventory_provider": {{ property.inventory_provider }},
- "inventory_type": {{ property.inventory_type }},
- "service_type": {{ property.service_type }},
- "customer_id": {{ property.customer_id }},
- "candidate_id": {{ property.candidate_id }}
- {% endfor %}
- ]
- }
- {% endfor %}
- ],
- "constraints": {
- {% set comma_main=joiner(",") %}
-
- {% if attribute_policy_list %} {{ comma_main() }} {% endif %}
- {% set comma=joiner(",") %}
- {% for attribute in attribute_policy_list %} {{ comma() }}
- attribute['identity'] : {
- "type": {{ attribute['type'] }},
- "demands": {{ attribute['demands'] }},
- "properties": {
- "evaluate": {
- "hypervisor": {{ attribute['property']['hypervisor'] }},
- "aic_version": {{ attribute['property']['aicVersion'] }},
- "aic_type": {{ attribute['property']['aicType'] }},
- "dataplane": {{ attribute['property']['datatype'] }},
- "network_roles": {{ attribute['property']['networkRoles'] }},
- "complex": {{ attribute['property']['complex'] }}
- }
- }
- }
- {% endfor %}
-
- {% if distance_to_location_policy_list %} {{ comma_main() }} {% endif %}
- {% set comma=joiner(",") %}
- {% for distance_location in distance_to_location_policy_list %} {{ comma() }}
- distance_location['identity'] : {
- "type": {{ distance_location['type'] }},
- "demands": {{ distance_location['demands'] }},
- "properties": {
- "distance": {{ distance_location['property']['distance'] }},
- "location": {{ distance_location['property']['location'] }}
- }
- }
- {% endfor %}
-
- {% if inventory_policy_list %} {{ comma_main() }} {% endif %}
- {% set comma=joiner(",") %}
- {% for inventory in inventory_policy_list %} {{ comma() }}
- inventory['identity'] : {
- "type": {{ inventory['type'] }},
- "demands": {{ inventory['demands'] }}
- }
- {% endfor %}
-
- {% if resource_instance_policy_list %} {{ comma_main() }} {% endif %}
- {% set comma=joiner(",") %}
- {% for resource_instance in resource_instance_policy_list %} {{ comma() }}
- resource_instance['identity'] : {
- "type": {{ resource_instance['type'] }},
- "demands": {{ resource_instance['demands'] }},
- "properties": {
- "controller": {{ resource_instance['property']['controller'] }},
- "request": {{ resource_instance['property']['request'] }}
- }
- }
- {% endfor %}
-
- {% if resource_region_policy_list %} {{ comma_main() }} {% endif %}
- {% set comma=joiner(",") %}
- {% for resource_region in resource_region_policy_list %} {{ comma() }}
- resource_region['identity'] : {
- "type": {{ resource_region['type'] }},
- "demands": {{ resource_region['demands'] }},
- "properties": {
- "controller": {{ resource_region['property']['controller'] }},
- "request": {{ resource_region['property']['request'] }}
- }
- }
- {% endfor %}
-
- {% if zone_policy_list %} {{ comma_main() }} {% endif %}
- {% set comma=joiner(",") %}
- {% for zone in zone_policy_list %} {{ comma() }}
- zone['identity'] : {
- "type": {{ zone['type'] }},
- "demands": {{ zone['demands'] }},
- "properties": {
- "qualifier": {{ resource_region['property']['qualifier'] }},
- "category": {{ resource_region['property']['category'] }}
- }
- }
- {% endfor %}
-
- {% if optmization_policy_list %} {{ comma_main() }} {% endif %}
- {% set comma=joiner(",") %}
- {% for optimization in optimization_policy_list %} {{ comma() }}
- "optimization" : {
- {{ optimization['objective'] }}: {
- "sum": [
- {% set comma2=joiner(",") %}
- {% for parameter in optimization['parameter'] %} {{ comma() }}
- {
- "product": [
- {{ parameter['weight'] }},
- {
- "distance_between": [{{ parameter['customerLocation'] }},{{ parameter['demand'] }}]
- }
- ]
- }
- {% endfor %}
- ]
- }
- }
- {% endfor %}
- }
- }
-}
diff --git a/osdf/templates/plc_opt_response.jsont b/osdf/templates/plc_opt_response.jsont
deleted file mode 100755
index e5709e7..0000000
--- a/osdf/templates/plc_opt_response.jsont
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "requestId": "{{requestId}}",
- "transactionId": "{{transacationId}}",
- "requestStatus": "{{requestStatus}}",
- "statusMessage": "{{statusMessage}}"
- "solutions": {
- "placementSolutions": {{ json.dumps(composite_solutions) }},
- "licenseSolutions":{{ json.dumps(license_solutions) }}
- }
-}
diff --git a/osdf/templates/policy_request.jsont b/osdf/templates/policy_request.jsont
deleted file mode 100755
index 3a9e201..0000000
--- a/osdf/templates/policy_request.jsont
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "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
deleted file mode 100755
index a60c8ff..0000000
--- a/osdf/templates/test_cms_nb_req_from_client.jsont
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "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
deleted file mode 100755
index 998ffb3..0000000
--- a/osdf/templates/test_plc_nb_req_from_client.jsont
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "requestInfo": {
- "requestId": "{{requestId}}",
- "sourceId": "{{sourceId}}",
- "optimizer": "{{optimizer}}",
- "numSolutions": {{numSolutions}},
- "timeout": {{timeout}},
- "callbackUrl" : "{{callbackUrl}}"
- },
- "placementInfo": {
- "modelInfo": {
- "modelType": "{{modelType}}",
- "modelInvariant": "{{modelInvariantId}}",
- "modelVersionId": "{{modelVersionId}}",
- "modelName": "{{modelName}}",
- "modelVersion": "{{modelVersion}}",
- "modelCustomizationId": "{{modelCustomizationId}}"
- },
- "subscriberInfo": {
- "globalSubscriberId": "{{globalSubscriberId}}",
- "subscriberName": "{{subscriberName}}",
- "subscriberCommonSiteId": "{{subscriberCommonSiteId}}",
- "ucpeHostName": "{{ucpeHostName}}"
- },
- "policyId": {{json.dumps(policyId)}},
- "vnfInfo": {
- "vnfType": "{{vnfType}}",
- "vnfPartNumber": "{{vnfPartNumber}}",
- "nominalThroughput": "{{nominalThroughput}}",
- "vnfSoftwareVersion": "{{vnfSoftwareVersion}}",
- "vnfManagementOption": "{{vnfManagementOption}}"
- },
- "vpnInfo": {
- "vpnId": "{{vpnId}}",
- "pvcId": "{{pvcId}}"
- },
- "serviceInfo": {
- "dhvServiceInfo": {
- "serviceInstanceId": "{{serviceInstanceId}}",
- "serviceType": "{{serviceType}}",
- "e2evpnkey": "{{e2evpnkey}}",
- "dhvSiteEffectiveTransportBandwidth": {{dhvSiteEffectiveTransportBandwidth}},
- "dhvIPSecTransportBandwidthUp": {{dhvIPSecTransportBandwidthUp}},
- "dhvIPSecTransportBandwidthDown": {{dhvIPSecTransportBandwidthDown}},
- "dhvIPSec2TransportBandwidthUp": {{dhvIPSec2TransportBandwidthUp}},
- "dhvIPSec2TransportBandwidthDown": {{dhvIPSec2TransportBandwidthDown}},
- "dhvVendorName": "{{dhvVendorName}}"
- }
- },
- "demandInfo": {{json.dumps(demandInfo)}}
- }
-}
diff --git a/osdf/utils/mdc_utils.py b/osdf/utils/mdc_utils.py
index 6da67bd..b98cbf0 100644
--- a/osdf/utils/mdc_utils.py
+++ b/osdf/utils/mdc_utils.py
@@ -42,11 +42,17 @@ def default_server_info():
MDC.put('serverIPAddress', server_ip_address)
-def mdc_from_json(request_json):
+def default_mdc():
MDC.put('instanceUUID', uuid.uuid1())
MDC.put('serviceName', 'OOF_OSDF')
MDC.put('threadID', threading.currentThread().getName())
default_server_info()
+ MDC.put('requestID', 'N/A')
+ MDC.put('partnerName', 'N/A')
+
+
+def mdc_from_json(request_json):
+ default_mdc()
MDC.put('requestID', request_json['requestInfo']['requestId'])
MDC.put('partnerName', request_json['requestInfo']['sourceId'])