From 430153e1a9489a86cf0ff7942eceb0bf5f1c170c Mon Sep 17 00:00:00 2001 From: vrvarma Date: Fri, 13 Dec 2019 10:24:55 -0500 Subject: osdf rearchitecture into apps and libs Change-Id: I2db2f8e252bd5e60807b2ffabf5a5b193a789f7a Signed-off-by: vrvarma Issue-ID: OPTFRA-637 --- osdf/apps/__init__.py | 2 + osdf/apps/baseapp.py | 166 ++++++++++++ osdf/config/__init__.py | 2 +- osdf/logging/osdf_logging.py | 1 + osdf/models/api/pciOptimizationRequest.py | 54 ---- osdf/models/api/pciOptimizationResponse.py | 46 ---- osdf/models/api/placementRequest.py | 105 -------- osdf/models/api/placementResponse.py | 64 ----- .../licenseopt/simple_license_allocation.py | 43 ---- osdf/optimizers/pciopt/configdb.py | 69 ----- osdf/optimizers/pciopt/pci_opt_processor.py | 122 --------- osdf/optimizers/pciopt/solver/__init__.py | 0 osdf/optimizers/pciopt/solver/min_confusion.mzn | 98 ------- .../optimizers/pciopt/solver/min_confusion_inl.mzn | 140 ---------- .../pciopt/solver/no_conflicts_no_confusion.mzn | 86 ------- osdf/optimizers/pciopt/solver/optimizer.py | 137 ---------- osdf/optimizers/pciopt/solver/pci_utils.py | 40 --- osdf/optimizers/placementopt/conductor/__init__.py | 17 -- .../placementopt/conductor/api_builder.py | 99 ------- .../optimizers/placementopt/conductor/conductor.py | 202 --------------- .../placementopt/conductor/remote_opt_processor.py | 81 ------ .../placementopt/conductor/translation.py | 283 --------------------- osdf/optimizers/routeopt/simple_route_opt.py | 153 ----------- osdf/templates/cms_opt_request.jsont | 35 --- osdf/templates/cms_opt_request.jsont_1707_v1 | 67 ----- osdf/templates/cms_opt_request_1702.jsont | 63 ----- osdf/templates/cms_opt_response.jsont | 8 - osdf/templates/conductor_interface.json | 39 --- osdf/templates/license_opt_request.jsont | 6 - osdf/templates/plc_opt_request.jsont | 142 ----------- osdf/templates/plc_opt_response.jsont | 10 - osdf/templates/policy_request.jsont | 3 - osdf/templates/test_cms_nb_req_from_client.jsont | 19 -- osdf/templates/test_plc_nb_req_from_client.jsont | 52 ---- osdf/utils/mdc_utils.py | 8 +- 35 files changed, 177 insertions(+), 2285 deletions(-) create mode 100644 osdf/apps/__init__.py create mode 100644 osdf/apps/baseapp.py delete mode 100644 osdf/models/api/pciOptimizationRequest.py delete mode 100644 osdf/models/api/pciOptimizationResponse.py delete mode 100644 osdf/models/api/placementRequest.py delete mode 100644 osdf/models/api/placementResponse.py delete mode 100644 osdf/optimizers/licenseopt/simple_license_allocation.py delete mode 100644 osdf/optimizers/pciopt/configdb.py delete mode 100644 osdf/optimizers/pciopt/pci_opt_processor.py delete mode 100644 osdf/optimizers/pciopt/solver/__init__.py delete mode 100644 osdf/optimizers/pciopt/solver/min_confusion.mzn delete mode 100644 osdf/optimizers/pciopt/solver/min_confusion_inl.mzn delete mode 100644 osdf/optimizers/pciopt/solver/no_conflicts_no_confusion.mzn delete mode 100644 osdf/optimizers/pciopt/solver/optimizer.py delete mode 100644 osdf/optimizers/pciopt/solver/pci_utils.py delete mode 100644 osdf/optimizers/placementopt/conductor/__init__.py delete mode 100644 osdf/optimizers/placementopt/conductor/api_builder.py delete mode 100755 osdf/optimizers/placementopt/conductor/conductor.py delete mode 100644 osdf/optimizers/placementopt/conductor/remote_opt_processor.py delete mode 100644 osdf/optimizers/placementopt/conductor/translation.py delete mode 100644 osdf/optimizers/routeopt/simple_route_opt.py delete mode 100755 osdf/templates/cms_opt_request.jsont delete mode 100755 osdf/templates/cms_opt_request.jsont_1707_v1 delete mode 100755 osdf/templates/cms_opt_request_1702.jsont delete mode 100644 osdf/templates/cms_opt_response.jsont delete mode 100755 osdf/templates/conductor_interface.json delete mode 100644 osdf/templates/license_opt_request.jsont delete mode 100755 osdf/templates/plc_opt_request.jsont delete mode 100755 osdf/templates/plc_opt_response.jsont delete mode 100755 osdf/templates/policy_request.jsont delete mode 100755 osdf/templates/test_cms_nb_req_from_client.jsont delete mode 100755 osdf/templates/test_plc_nb_req_from_client.jsont (limited to 'osdf') 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 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']) -- cgit 1.2.3-korg