diff --git a/doc/SpecifyingApplications/CreatingConfigFile/CreatingConfigFile.md b/doc/SpecifyingApplications/CreatingConfigFile/CreatingConfigFile.md index 508aeca3..96f6ed9c 100644 --- a/doc/SpecifyingApplications/CreatingConfigFile/CreatingConfigFile.md +++ b/doc/SpecifyingApplications/CreatingConfigFile/CreatingConfigFile.md @@ -65,6 +65,8 @@ Several need to be added, and it is recommended to copy and paste the existing o - After you updated the OperationClients at all the HttpClients, double check whether the ordering of the OperationClients is consistent with the ServiceList. - After assuring that, double check, whether the abbreviation of the application's name inside the UUIDs of all the OperationClients, HttpClients and TcpClients is correct. - Finally, double check the sequence number inside the UUIDs of all the OperationClients, HttpClients and TcpClients. + +- Also ensure that the [operationKey](./OperationKeys.md) fields of OperationClients and OperationServers are set correctly. #### ForwardingConstructs diff --git a/doc/SpecifyingApplications/CreatingConfigFile/OperationKeys.md b/doc/SpecifyingApplications/CreatingConfigFile/OperationKeys.md new file mode 100644 index 00000000..cc8b68c4 --- /dev/null +++ b/doc/SpecifyingApplications/CreatingConfigFile/OperationKeys.md @@ -0,0 +1,32 @@ +# Setting the correct operationKeys in the CONFIGfile + +This document describes how to assign the correct operationKeys to OperationClients and OperationServers in the configFile. + + +### Concept + +- For some operations an operationKey needs to be provided, whereas other operations do not require an operationKey to be provided. +- Whether providing an operationKey is required is defined in the `security` section of a given operations specification. +- Currently the following three options are available: + 1. `apiAuthKey`: an operationKey needs to be provided + - operationKey = default operationKey = "Operation key not yet provided." + 2. `basicAuth`: instead of an operationKey an authorization code needs to be provided upon request execution + - operationKey = "n.a." + 3. no security tag at all: no authentication is required. + - operationKey = "n.a." + +#### Examples +The following code snippets show OAS examples for all three options: + +| OAS Example | Info | +|------------------------------------------------------|--------------------------------------------------------------------------| +| ![apiKeyAuth](./pictures/example_oas_apiKeyAuth.png) | operationKey required,
operationKey = default operationKey | +| ![basicAuth](./pictures/example_oas_basicAuth.png) | requires authorizationCode instead of operationKey,
operationKey = n.a. | +| ![noAuth](./pictures/example_oas_noAuth.png) | operationKey = n.a. | + +Examples from ConfigFile: +| ConfigFile Example | ConfigFile | +|---------------|-----------------------------------------------------------------| +| 1. apiKeyAuth | ![apiKeyAuthConf](./pictures/example_configFile_apiKeyAuth.png) | +| 2. basicAuth | ![basicAuthConf](./pictures/example_configFile_basicAuth.png) | +| 3. noAuth | ![noAuthConf](./pictures/example_configFile_noAuth.png) | \ No newline at end of file diff --git a/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_apiKeyAuth.png b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_apiKeyAuth.png new file mode 100644 index 00000000..85e5524f Binary files /dev/null and b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_apiKeyAuth.png differ diff --git a/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_basicAuth.png b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_basicAuth.png new file mode 100644 index 00000000..546a6997 Binary files /dev/null and b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_basicAuth.png differ diff --git a/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_noAuth.png b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_noAuth.png new file mode 100644 index 00000000..187b1455 Binary files /dev/null and b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_configFile_noAuth.png differ diff --git a/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_apiKeyAuth.png b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_apiKeyAuth.png new file mode 100644 index 00000000..6f761fad Binary files /dev/null and b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_apiKeyAuth.png differ diff --git a/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_basicAuth.png b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_basicAuth.png new file mode 100644 index 00000000..f53d2a34 Binary files /dev/null and b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_basicAuth.png differ diff --git a/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_noAuth.png b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_noAuth.png new file mode 100644 index 00000000..5f0cef32 Binary files /dev/null and b/doc/SpecifyingApplications/CreatingConfigFile/pictures/example_oas_noAuth.png differ diff --git a/doc/SpecifyingApplications/HowToDefineErrorMessages/HowToDefineErrorMessages.md b/doc/SpecifyingApplications/HowToDefineErrorMessages/HowToDefineErrorMessages.md new file mode 100644 index 00000000..4af6fe92 --- /dev/null +++ b/doc/SpecifyingApplications/HowToDefineErrorMessages/HowToDefineErrorMessages.md @@ -0,0 +1,59 @@ +# How to define Error Messages + +Error responses should be meaningful and helpful for handling the errors. +It should not only inform about a problem, but also assist in dealing with it. +Ideally, an error message provides a machine- and human-readable recommendation for the next step to be taken (e.g. as part of an automation). + +How to define error responses in the OAS: +1. **List possible reasons** why the requested data cannot be provided or the requested service cannot be performed. +2. **Reasons for failure** should be **grouped into** different **expected behaviors of the client** + - e.g., *"try again later"*, *"make sure the device is mounted first"*. +3. **Groups of failures** with the **same expected client behavior** should be **associated with a response code** + - according to https://developer.mozilla.org/en-US/docs/Web/HTTP/Status. + - If an appropriate response code could not be found, define a new one. +4. If not already covered by the ApplicationPattern, **add** the **new responseCode to** the **responses of the affected service**. +5. The **response definition for a specific responseCode must be homogeneous** + - at least within the scope of the application (harmonization across all applications will be done at a later stage, by consolidating individual definitions into an updated applicationPattern). + - To ensure this, the response definition at an individual service should only reference a concrete definition in the common components section (`$ref: '#/components/responses/{responseCode}`). +6. The **concrete definition in** the **common components section** is **identified by the responseCode**. +7. It must begin with a **description statement**. + - The description statement is addressed to the implementor of the server (application under specification). + - It defines the conditions for sending a response with this code. + - Example: *"Response to be sent whenever the number of currently executed requests reaches the maximum defined in the instance of IntegerProfile whose name contains limitOfParallelRequestsAt and the service name."* +6. Some "standard" response codes from the list above define **additional headers or parameters**. + - Such additional headers and parameters must also be included in the response definition in the common components, even if they are not used within the scope of this application. +7. If **additional attributes** are **required to manage the client's behavior**, they shall be **included in** the **body of the definitions** in the common components. +8. **code and message attributes shall always be supported**. + - They shall be available for the implementers to detail the reason of failure. +9. If an **additional attribute** would be required to pass a **predefined message**, that message shall be **defined as an enumeration** with only a single value. +10. If sending a **response implies** a **specific expectation to the client's behavior**, this expectation should be explicitly expressed by an **expectation-to-the-client attribute**. + - This attribute should be an **enumeration** with a single value. + - This value should contain a statement that is understood by both an automation implementer and a human user. + +Example: +``` +components: + responses: + 429: + description: 'Response to be send whenever the number of currently executed requests reached the maximum defined in the instance of IntegerProfile with its name containing limitOfParallelRequestsAt and the service name.' + content: + application/json: + schema: + type: object + required: + - code + - message + - expectation-to-the-client + properties: + code: + type: integer + format: int32 + message: + type: string + enum: + - 'The maximum number of requests that can be handled by this service in parallel has been reached' + expectation-to-the-client: + type: string + enum: + - 'Please try again later' +``` diff --git a/doc/SpecifyingApplications/SpecifyingApplications.md b/doc/SpecifyingApplications/SpecifyingApplications.md index 320b3d01..bdf2ffef 100644 --- a/doc/SpecifyingApplications/SpecifyingApplications.md +++ b/doc/SpecifyingApplications/SpecifyingApplications.md @@ -89,7 +89,8 @@ The ForwardingList must describe all relationships between events and reactions The OpenApiSpecification (OAS) represents the detailed specification of the REST API of the application. **Concepts** -- [Structure of the OAS](./StructureOfOas/StructureOfOas.md) +- [Structure of the OAS](./StructureOfOas/StructureOfOas.md) +- [How to define error messages](./HowToDefineErrorMessages/HowToDefineErrorMessages.md) **Step-by-Step Guidelines** - [Creating the OAS](./CreatingOas/CreatingOas.md) diff --git a/server/applicationPattern/applicationPattern/commons/AppCommons.js b/server/applicationPattern/applicationPattern/commons/AppCommons.js index 3da21a8c..14652caa 100644 --- a/server/applicationPattern/applicationPattern/commons/AppCommons.js +++ b/server/applicationPattern/applicationPattern/commons/AppCommons.js @@ -69,7 +69,8 @@ async function validateOperationKey(request, scopes, schema) { */ // eslint-disable-next-line no-unused-vars async function validateBasicAuth(request, scopes, schema) { - const authStatus = await authorizingService.isAuthorized(request.headers.authorization, request.method); + let pathDefinedInOpenApi = request.openapi.openApiRoute; + const authStatus = await authorizingService.isAuthorized(request.headers.authorization, request.method, pathDefinedInOpenApi); if (authStatus.isAuthorized == true) { return true; } else { diff --git a/server/applicationPattern/applicationPattern/onfModel/models/ProfileCollection.js b/server/applicationPattern/applicationPattern/onfModel/models/ProfileCollection.js index 12da20b0..95ef2611 100644 --- a/server/applicationPattern/applicationPattern/onfModel/models/ProfileCollection.js +++ b/server/applicationPattern/applicationPattern/onfModel/models/ProfileCollection.js @@ -17,7 +17,6 @@ const Profile = require('./Profile'); class ProfileCollection { /** - * @deprecated use getProfileListForProfileNameAsync * @description This function returns the profile list from /core-model-1-4:control-construct/profile-collection/profile. * @returns {promise} list {profile list} **/ diff --git a/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationClientInterface.js b/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationClientInterface.js index 187dedef..f3a1b18c 100644 --- a/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationClientInterface.js +++ b/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationClientInterface.js @@ -16,7 +16,9 @@ const tcpClientInterface = require('./TcpClientInterface'); const onfPaths = require('../../constants/OnfPaths'); const onfAttributes = require('../../constants/OnfAttributes'); const fileOperation = require('../../../databaseDriver/JSONDriver'); - +global.operationKeyNotificationChannel = []; +global.notificationChannelSubscriber = []; +global.isNotificationChannelON = false; /** * @extends LayerProtocol */ @@ -121,7 +123,7 @@ class OperationClientInterface extends LayerProtocol { } return undefined; } - + /** * @description This function returns the detailedLoggingIsOn attribute of the operation client. * @param {String} operationClientUuid : uuid of the operation client ,the value should be a valid string @@ -201,15 +203,23 @@ class OperationClientInterface extends LayerProtocol { * @param {String} operationClientUuid : uuid of the http client ,the value should be a valid string * in the pattern '-\d+-\d+-\d+-op-client-\d+$' * @param {String} operationKey : key that needs to be updated. - * @returns {Promise} true|false + * @returns {Promise} isOperationKeySet **/ static async setOperationKeyAsync(operationClientUuid, operationKey) { - let operationKeyPath = onfPaths.OPERATION_CLIENT_OPERATION_KEY.replace( - "{uuid}", operationClientUuid); - return await fileOperation.writeToDatabaseAsync( - operationKeyPath, - operationKey, - false); + let isOperationKeySet = false + let oldoperationKey = await this.getOperationKeyAsync(operationClientUuid); + if (oldoperationKey != operationKey) { + let operationKeyPath = onfPaths.OPERATION_CLIENT_OPERATION_KEY.replace( + "{uuid}", operationClientUuid); + isOperationKeySet = await fileOperation.writeToDatabaseAsync( + operationKeyPath, + operationKey, + false); + } + if (isOperationKeySet == true || oldoperationKey == operationKey) { + this.addOperationKeyUpdateToNotificationChannel(operationClientUuid); + } + return isOperationKeySet; } /** @@ -289,6 +299,92 @@ class OperationClientInterface extends LayerProtocol { const layerProtocolName = layerProtocol[onfAttributes.LAYER_PROTOCOL.LAYER_PROTOCOL_NAME]; return LayerProtocol.layerProtocolNameEnum.OPERATION_CLIENT === layerProtocolName; } + + /** + * @param {HRTime} timeStampIdentifier an identifier the process that turns ON the notification channel + * @return {boolean} result whether the notificationChannel is turned ON or not + */ + static turnONNotificationChannel(timeStampIdentifier) { + try { + if (!global.notificationChannelSubscriber.includes(timeStampIdentifier)) { + global.notificationChannelSubscriber.push(timeStampIdentifier); + } + global.isNotificationChannelON = true; + console.log("******* Notification channel for Operation key is turned ON ***************"); + return global.isNotificationChannelON; + } catch (error) { + return false; + } + } + + /** + * @param {HRTime} timeStampAsIdentifier an identifier the process that turns OFF the notification channel + * @return {boolean} result whether the notificationChannel is turned OFF or not + */ + static turnOFFNotificationChannel(timeStampAsIdentifier) { + try { + if (global.notificationChannelSubscriber.includes(timeStampAsIdentifier)) { + global.notificationChannelSubscriber.forEach((element, index) => { + if (element == timeStampAsIdentifier) { + global.notificationChannelSubscriber = global.notificationChannelSubscriber.splice(index, 1); + } + }); + } + if (global.notificationChannelSubscriber.length > 0) { + global.isNotificationChannelON = false; + console.log("******* Notification channel for Operation key is turned OFF ***************"); + } + return !global.isNotificationChannelON; + } catch (error) { + return false; + } + } + + /** + * function to add notifications to the global operationKeyNotificationChannel + * @param {String} operationClientUuid of the operationKey updated instance + */ + static async addOperationKeyUpdateToNotificationChannel(operationClientUuid) { + try { + if (global.isNotificationChannelON) { + let operationKeyNotification = { + "eventTime": new Date(), + "operationClientUuid": operationClientUuid + }; + console.log("Notification pushed :" + operationKeyNotification.eventTime + "," + operationKeyNotification.operationClientUuid); + global.operationKeyNotificationChannel.push(operationKeyNotification); + } + } catch (error) { + console.log(error); + } + } + + /** + * This function waits for a desired time until an operation-key updation is received for a client + * @param {String} operationClientUuid for which the an operation-key update is monitored + * @param {Date} timestampOfCurrentRequest shall be used to monitor whether operation-key is updated after this event's occurance + * @param {Integer} waitTime will be the maximum time to wait for an operation-key update in Seconds + * @returns {promise} boolean that represents an operation-key update + */ + static async waitUntilOperationKeyIsUpdated(operationClientUuid, timestampOfCurrentRequest, waitTime) { + let startTime = process.hrtime(); + console.log("Waiting to receive operation key update for the operationClientUuid " + operationClientUuid); + return await new Promise(resolve => { + const interval = setInterval(() => { + let operationKeyUpdated = isOperationKeyUpdated(operationClientUuid, timestampOfCurrentRequest); + let waitTimeExceeded = isWaitTimeExceeded(startTime, waitTime); + if (operationKeyUpdated == true) { + console.log("Operation key update received for the operationClientUuid " + operationClientUuid); + resolve(true); + clearInterval(interval); + } else if (waitTimeExceeded == true) { + console.log("Waiting time exceeded for receiving operation key for the operationClientUuid " + operationClientUuid); + resolve(false); + clearInterval(interval); + } + }, 100); + }); + } } /** @@ -309,4 +405,42 @@ function getConfiguredRemoteAddress(remoteAddress) { return remoteAddress; } -module.exports = OperationClientInterface; +/** + * + * @param {HRTime} startTime of the process + * @param {Integer} waitingTime of the process in Seconds + * @returns + */ +function isWaitTimeExceeded(startTime, waitingTime) { + let NanoSecondPerSecond = 1e9; + let executionTime = process.hrtime(startTime); + let executionTimeInseconds = (executionTime[0] * NanoSecondPerSecond + executionTime[1]) / NanoSecondPerSecond + if (executionTimeInseconds >= waitingTime) { + return true + } else { + return false; + } +} + +/** + * + * @param {String} operationClientUuid uuid of the operation client interface + * @param {HRTime} eventTime of the process + * @returns + */ +function isOperationKeyUpdated(operationClientUuid, eventTime) { + let result = false; + console.log(operationClientUuid + "," + eventTime); + let oKNotificationChannel = global.operationKeyNotificationChannel; + oKNotificationChannel.filter((notification) => { + console.log("*****************************************"); + console.log(notification.operationClientUuid); + console.log(operationClientUuid); + if (notification.operationClientUuid == operationClientUuid && notification.eventTime > eventTime) { + result = true; + } + }); + return result; +} + +module.exports = OperationClientInterface; \ No newline at end of file diff --git a/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationServerInterface.js b/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationServerInterface.js index a4dc5411..5933e88e 100644 --- a/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationServerInterface.js +++ b/server/applicationPattern/applicationPattern/onfModel/models/layerProtocols/OperationServerInterface.js @@ -12,6 +12,8 @@ const LayerProtocol = require('../LayerProtocol'); const onfPaths = require('../../constants/OnfPaths'); const onfAttributes = require('../../constants/OnfAttributes'); const fileOperation = require('../../../databaseDriver/JSONDriver'); +const ForwardingDomain = require('../../models/ForwardingDomain'); +const FcPort = require('../FcPort'); /** * @extends LayerProtocol */ @@ -209,6 +211,26 @@ class OperationServerInterface extends LayerProtocol { } } + /** + * @description This function returns the input operationServer operationName of the fowarding. + * @param {String} forwardingName: the value should be a valid forwardingName + * @returns {Promise} operationServerName + **/ + + static async getInputOperationServerNameFromForwarding(forwardingName) { + let forwardConstruct = await ForwardingDomain.getForwardingConstructForTheForwardingNameAsync(forwardingName) + if (forwardConstruct === undefined) { + return undefined; + } + let fcPorts = forwardConstruct[onfAttributes.FORWARDING_CONSTRUCT.FC_PORT]; + let fcPortOutput = fcPorts.filter( + fcPort => fcPort[onfAttributes.FC_PORT.PORT_DIRECTION] === FcPort.portDirectionEnum.INPUT + )[0]; + let operationServerUuid = fcPortOutput[onfAttributes.FC_PORT.LOGICAL_TERMINATION_POINT]; + let operationServerName = await this.getOperationNameAsync(operationServerUuid); + return operationServerName; + } + /** * @description Determines if given UUID belongs to a server operation. * @param {String} operationUuid UUID to be checked diff --git a/server/applicationPattern/applicationPattern/onfModel/models/profile/IntegerProfile.js b/server/applicationPattern/applicationPattern/onfModel/models/profile/IntegerProfile.js index f121a4d1..d12ebf36 100644 --- a/server/applicationPattern/applicationPattern/onfModel/models/profile/IntegerProfile.js +++ b/server/applicationPattern/applicationPattern/onfModel/models/profile/IntegerProfile.js @@ -122,7 +122,7 @@ class IntegerProfile extends Profile { * @deprecated should be removed * @description This function returns the maxmimum value for the integer profile. * @param {String} integerProfileUuid : the value should be a valid string in the pattern '^([a-z]{2,6})-([0-9]{1,2})-([0-9]{1,2})-([0-9]{1,2})-integer-p-([0-9]{3})$' - * @returns {promise} string {approvalStatus} + * @returns {promise} string {integerValue} **/ static async getIntegerValueAsync(integerProfileUuid) { return new Promise(async function (resolve, reject) { @@ -146,40 +146,27 @@ class IntegerProfile extends Profile { }); } - - static async maximumWaitTimeToReceiveOperationKey() { - let intervalInMinutes - let profileList = await ProfileCollection.getProfileListAsync(); - for (let i = 0; i < profileList.length; i++) { - let profileInstance = profileList[i]; - let profileName = profileInstance[onfAttributes.PROFILE.PROFILE_NAME]; - if (profileName == "integer-profile-1-0:PROFILE_NAME_TYPE_INTEGER_PROFILE") { - let Integerval = profileInstance[onfAttributes.INTEGER_PROFILE.PAC][onfAttributes.INTEGER_PROFILE.CAPABILITY][onfAttributes.INTEGER_PROFILE.INTEGER_NAME] - if (Integerval == 'maximumWaitTimeToReceiveOperationKey') { - intervalInMinutes = profileInstance[onfAttributes.INTEGER_PROFILE.PAC][onfAttributes.INTEGER_PROFILE.CONFIGURATION][onfAttributes.INTEGER_PROFILE.INTEGER_VALUE] - break; - } - } - } - return intervalInMinutes; - } - - static async maximumNumberOfAttemptsToCreateLink() { - let numberOfAttempt +/** + * @description This function returns the configured value for the integer profile. + * @param {String} integerProfileName : name of the integer profile + * @returns {promise} string {integerValue} + **/ + static async getIntegerValueForTheIntegerProfileNameAsync(integerProfileName) { + let integerValue let profileList = await ProfileCollection.getProfileListAsync(); for (let i = 0; i < profileList.length; i++) { let profileInstance = profileList[i]; let profileName = profileInstance[onfAttributes.PROFILE.PROFILE_NAME]; if (profileName == "integer-profile-1-0:PROFILE_NAME_TYPE_INTEGER_PROFILE") { let Integerval = profileInstance[onfAttributes.INTEGER_PROFILE.PAC][onfAttributes.INTEGER_PROFILE.CAPABILITY][onfAttributes.INTEGER_PROFILE.INTEGER_NAME] - if (Integerval == 'maximumNumberOfAttemptsToCreateLink') { - numberOfAttempt = profileInstance[onfAttributes.INTEGER_PROFILE.PAC][onfAttributes.INTEGER_PROFILE.CONFIGURATION][onfAttributes.INTEGER_PROFILE.INTEGER_VALUE] + if (Integerval == integerProfileName) { + integerValue = profileInstance[onfAttributes.INTEGER_PROFILE.PAC][onfAttributes.INTEGER_PROFILE.CONFIGURATION][onfAttributes.INTEGER_PROFILE.INTEGER_VALUE] break; } } } - return numberOfAttempt; - } + return integerValue; + } } module.exports = IntegerProfile; diff --git a/server/applicationPattern/applicationPattern/onfModel/services/LogicalTerminationPointServices.js b/server/applicationPattern/applicationPattern/onfModel/services/LogicalTerminationPointServices.js index 66349f26..1c2a290d 100644 --- a/server/applicationPattern/applicationPattern/onfModel/services/LogicalTerminationPointServices.js +++ b/server/applicationPattern/applicationPattern/onfModel/services/LogicalTerminationPointServices.js @@ -202,6 +202,7 @@ async function createLtpInstanceGroupAsync(logicalTerminationPointConfigurationI async function updateLtpInstanceGroupAsync(ltpConfigurationInput, isApplicationRO) { const httpClientUuid = ltpConfigurationInput.httpClientUuid; const releaseNumber = ltpConfigurationInput.releaseNumber; + const applicationName = ltpConfigurationInput.applicationName ? ltpConfigurationInput.applicationName : undefined; const tcpList = ltpConfigurationInput.tcpList; const operationServerName = ltpConfigurationInput.operationServerName; const operationNamesByAttributes = ltpConfigurationInput.operationNamesByAttributes; @@ -235,7 +236,8 @@ async function updateLtpInstanceGroupAsync(ltpConfigurationInput, isApplicationR const httpClientConfigurationStatus = await updateHttpClientLtpAsync( httpClientUuid, releaseNumber, - operationClientListChanged + operationClientListChanged, + applicationName ) return new LogicalTerminationPointConfigurationStatus( operationClientConfigurationStatusList, @@ -268,7 +270,7 @@ async function createHttpClientLtpAsync(applicationName, releaseNumber) { * @param {Boolean} isOperationClientChanged if there was a change with any of this http-client operation-client * @return {Promise} **/ -async function updateHttpClientLtpAsync(httpClientUuid, releaseNumber, isOperationClientChanged) { +async function updateHttpClientLtpAsync(httpClientUuid, releaseNumber, isOperationClientChanged, applicationName) { let isUpdated = false; if (isOperationClientChanged) { isUpdated = true; @@ -279,6 +281,12 @@ async function updateHttpClientLtpAsync(httpClientUuid, releaseNumber, isOperati httpClientUuid, releaseNumber ); } + const existingApplicationName = await HttpClientInterface.getApplicationNameAsync(httpClientUuid); + if (applicationName && existingApplicationName !== applicationName) { + isUpdated = await HttpClientInterface.setApplicationNameAsync( + httpClientUuid, applicationName + ); + } return new ConfigurationStatus(httpClientUuid, '', isUpdated); } diff --git a/server/applicationPattern/applicationPattern/rest/client/RequestBuilder.js b/server/applicationPattern/applicationPattern/rest/client/RequestBuilder.js index 843c86ec..f12a25ea 100644 --- a/server/applicationPattern/applicationPattern/rest/client/RequestBuilder.js +++ b/server/applicationPattern/applicationPattern/rest/client/RequestBuilder.js @@ -56,7 +56,9 @@ exports.BuildAndTriggerRestRequest = async function (operationClientUuid, method return error.response; } else if (error.request) { console.log(`Request errored with ${error}`); - return new createHttpError.RequestTimeout(); + let requestTimeoutError = new createHttpError.RequestTimeout(); + requestTimeoutError.url = error.config ? error.config.url ? error.config.url : undefined : undefined; + return requestTimeoutError; } console.log(`Unknown request error: ${error}`); return new createHttpError.InternalServerError(); diff --git a/server/applicationPattern/applicationPattern/rest/client/eventDispatcher.js b/server/applicationPattern/applicationPattern/rest/client/eventDispatcher.js index 3345579c..a29e502d 100644 --- a/server/applicationPattern/applicationPattern/rest/client/eventDispatcher.js +++ b/server/applicationPattern/applicationPattern/rest/client/eventDispatcher.js @@ -61,7 +61,18 @@ exports.dispatchEvent = function (operationClientUuid, httpRequestBody, user, xC if (responseCode.toString().startsWith("2")) { result = true; } else if (responseCode == 408) { - recordServiceRequestFromClient(serverApplicationName, serverApplicationReleaseNumber, xCorrelator, traceIndicator, user, originator, operationName, responseCode, httpRequestBody, response.data) + recordServiceRequestFromClient( + serverApplicationName, + serverApplicationReleaseNumber, + xCorrelator, + traceIndicator, + user, + originator, + operationName, + responseCode, + httpRequestBody, + response.data, + response.url) .catch((error) => console.log(`record service request ${JSON.stringify({ xCorrelator, traceIndicator, diff --git a/server/applicationPattern/applicationPattern/services/AuthorizingService.js b/server/applicationPattern/applicationPattern/services/AuthorizingService.js index 47d69d54..02e88a4d 100644 --- a/server/applicationPattern/applicationPattern/services/AuthorizingService.js +++ b/server/applicationPattern/applicationPattern/services/AuthorizingService.js @@ -16,7 +16,7 @@ const FcPort = require('../onfModel/models/FcPort'); * @param {String} method is the https method name * @returns {Promise} authStatus */ -exports.isAuthorized = async function (authorizationCode, method) { +exports.isAuthorized = async function (authorizationCode, method, operationName) { let authStatus = { "isAuthorized": false } @@ -26,8 +26,8 @@ exports.isAuthorized = async function (authorizationCode, method) { let applicationName = await HttpServerInterface.getApplicationNameAsync(); let applicationReleaseNumber = await HttpServerInterface.getReleaseNumberAsync(); let httpRequestHeader = onfAttributeFormatter.modifyJsonObjectKeysToKebabCase(new RequestHeader(userName, applicationName, "", "", "unknown", operationKey)); - let httpRequestBody = formulateRequestBody(applicationName, applicationReleaseNumber, authorizationCode, method); - let response = await RequestBuilder.BuildAndTriggerRestRequest(operationClientUuid, "POST", httpRequestHeader, httpRequestBody); + let httpRequestBody = formulateRequestBody(applicationName, applicationReleaseNumber, authorizationCode, method, operationName); + let response = await RequestBuilder.BuildAndTriggerRestRequest(operationClientUuid, "POST", httpRequestHeader, httpRequestBody, undefined); if (response && response.status === 200) { if (response.data["oam-request-is-approved"] == true) { authStatus.isAuthorized = true; @@ -50,18 +50,19 @@ exports.isAuthorized = async function (authorizationCode, method) { * @param {String} method HTTP method of the OAM layer call. It can be PUT,GET * @returns {Object} formulated requestBody */ - function formulateRequestBody(applicationName, releaseNumber, authorizationCode, method) { + function formulateRequestBody(applicationName, releaseNumber, authorizationCode, method, operationName) { return { "application-name": applicationName, "release-number": releaseNumber, "Authorization": authorizationCode, - "method": method + "method": method, + "operation-name": operationName }; } async function getOperationClientToAuthenticateTheRequest() { let forwardingConstruct = await ForwardingDomain.getForwardingConstructForTheForwardingNameAsync( - "OamRequestCausesInquiryForAuthentication"); + "BasicAuthRequestCausesInquiryForAuthentication"); if (forwardingConstruct) { let fcPortList = forwardingConstruct["fc-port"]; for (let fcPort of fcPortList) { diff --git a/server/applicationPattern/applicationPattern/services/ExecutionAndTraceService.js b/server/applicationPattern/applicationPattern/services/ExecutionAndTraceService.js index a829a5c7..029d0480 100644 --- a/server/applicationPattern/applicationPattern/services/ExecutionAndTraceService.js +++ b/server/applicationPattern/applicationPattern/services/ExecutionAndTraceService.js @@ -22,10 +22,11 @@ const moment = require('moment'); * @param {number} responseCode response code of the rest call execution
* @param {object} requestBody request body
* @param {object} responseBody response body
+ * @param {String} url complete url of the request * @returns {Promise} returns true if the operation is successful. Promise is never rejected.
*/ exports.recordServiceRequestFromClient = async function (serverApplicationName, serverApplicationReleaseNumber, xCorrelator, traceIndicator, userName, originator, - operationName, responseCode, requestBody, responseBody) { + operationName, responseCode, requestBody, responseBody, url) { let httpRequestBody = {}; try { let operationClientUuid = await getOperationClientToLogServiceRequest(); @@ -37,7 +38,7 @@ exports.recordServiceRequestFromClient = async function (serverApplicationName, let stringifiedRequestBody = JSON.stringify(requestBody); let stringifiedResponseBody = JSON.stringify(responseBody); let httpRequestBody = formulateRequestBody(xCorrelator, traceIndicator, userName, originator, serverApplicationName, serverApplicationReleaseNumber, - operationName, responseCode, timestamp, stringifiedRequestBody, stringifiedResponseBody, detailedLoggingIsOn); + operationName, responseCode, timestamp, stringifiedRequestBody, stringifiedResponseBody, detailedLoggingIsOn, url); let response = await RequestBuilder.BuildAndTriggerRestRequest(operationClientUuid, "POST", httpRequestHeader, httpRequestBody); let responseCodeValue = response.status.toString(); if (responseCodeValue.startsWith("2")) { @@ -61,10 +62,11 @@ exports.recordServiceRequestFromClient = async function (serverApplicationName, * @param {number} responseCode response code of the rest call execution
* @param {object} requestBody request body
* @param {object} responseBody response body
+ * @param {String} execTime time taken to execute this request * @returns {Promise} returns true if the operation is successful. Promise is never rejected.
*/ exports.recordServiceRequest = async function (xCorrelator, traceIndicator, userName, originator, - operationName, responseCode, requestBody, responseBody) { + operationName, responseCode, requestBody, responseBody, execTime) { let httpRequestBody = {}; try { let operationClientUuid = await getOperationClientToLogServiceRequest(); @@ -77,7 +79,7 @@ exports.recordServiceRequest = async function (xCorrelator, traceIndicator, user let stringifiedRequestBody = JSON.stringify(requestBody); let stringifiedResponseBody = JSON.stringify(responseBody); let httpRequestBody = formulateRequestBody(xCorrelator, traceIndicator, userName, originator, applicationName, applicationReleaseNumber, - operationName, responseCode, timestamp, stringifiedRequestBody, stringifiedResponseBody, detailedLoggingIsOn); + operationName, responseCode, timestamp, stringifiedRequestBody, stringifiedResponseBody, detailedLoggingIsOn, undefined, execTime); let response = await RequestBuilder.BuildAndTriggerRestRequest(operationClientUuid, "POST", httpRequestHeader, httpRequestBody); let responseCodeValue = response.status.toString(); if (responseCodeValue.startsWith("2")) { @@ -108,7 +110,7 @@ exports.recordServiceRequest = async function (xCorrelator, traceIndicator, user * @returns {Object} return the formulated responseBody
*/ function formulateRequestBody(xCorrelator, traceIndicator, userName, originator, applicationName, applicationReleaseNumber, - operationName, responseCode, timestamp, stringifiedBody, stringifiedResponse, detailedLoggingIsOn) { + operationName, responseCode, timestamp, stringifiedBody, stringifiedResponse, detailedLoggingIsOn, Url, execTime) { let httpRequestBody = { "x-correlator": xCorrelator, "trace-indicator": traceIndicator, @@ -117,10 +119,12 @@ function formulateRequestBody(xCorrelator, traceIndicator, userName, originator, "application-name": applicationName, "release-number": applicationReleaseNumber, "operation-name": operationName, - "response-code": responseCode + "response-code": responseCode, + "timestamp" : timestamp, + "url": Url, + "exec-time": execTime }; if (detailedLoggingIsOn) { - httpRequestBody["timestamp"] = timestamp; httpRequestBody["stringified-body"] = stringifiedBody; httpRequestBody["stringified-response"] = stringifiedResponse; } diff --git a/server/basicServices/basicServices/BasicServicesOperationsMapping.js b/server/basicServices/basicServices/BasicServicesOperationsMapping.js index fe42d9de..990159b1 100644 --- a/server/basicServices/basicServices/BasicServicesOperationsMapping.js +++ b/server/basicServices/basicServices/BasicServicesOperationsMapping.js @@ -41,6 +41,13 @@ module.exports.basicServicesOperationsMapping = "sequence": "000" } }, + "/v1/inquire-basic-auth-approvals": + { + "basic-auth-approval-operation": { + "api-segment": "bs", + "sequence": "000" + } + }, "/v1/redirect-topology-change-information": { "topology-operation-application-update": { "api-segment": "bm", diff --git a/server/basicServices/basicServices/BasicServicesService.js b/server/basicServices/basicServices/BasicServicesService.js index f7c2c686..422e8197 100644 --- a/server/basicServices/basicServices/BasicServicesService.js +++ b/server/basicServices/basicServices/BasicServicesService.js @@ -34,6 +34,69 @@ const controlConstruct = require('onf-core-model-ap/applicationPattern/onfModel/ const basicServicesOperationsMapping = require('./BasicServicesOperationsMapping'); const genericRepresentation = require('./GenericRepresentation'); const createHttpError = require('http-errors'); +const HttpServerInterface = require('onf-core-model-ap/applicationPattern/onfModel/models/layerProtocols/HttpServerInterface'); +const OperationClientInterface = require('onf-core-model-ap/applicationPattern/onfModel/models/layerProtocols/OperationClientInterface'); + +const integerProfile = require('onf-core-model-ap/applicationPattern/onfModel/models/profile/IntegerProfile'); +/** + * Removes application from configuration and application data + * + * body V1_disposeremaindersofderegisteredapplication_body + * user String User identifier from the system starting the service call + * originator String 'Identification for the system consuming the API, as defined in [/core-model-1-4:control-construct/logical-termination-point={uuid}/layer-protocol=0/http-client-interface-1-0:http-client-interface-pac/http-client-interface-configuration/application-name]' + * xCorrelator String UUID for the service execution flow that allows to correlate requests and responses + * traceIndicator String Sequence of request numbers along the flow + * customerJourney String Holds information supporting customer’s journey to which the execution applies + * no response value expected for this operation + **/ +exports.disposeRemaindersOfDeregisteredApplication = async function (body, user, originator, xCorrelator, traceIndicator, customerJourney, operationServerName, newReleaseFWName) { + let applicationName = body["application-name"]; + let applicationReleaseNumber = body["release-number"]; + + let httpClientUuid = await httpClientInterface.getHttpClientUuidExcludingOldReleaseAndNewRelease( + applicationName, + applicationReleaseNumber, + newReleaseFWName + ); + let ltpConfigurationStatus = await LogicalTerminationPointService.deleteApplicationLtpsAsync( + httpClientUuid + ); + + /**************************************************************************************** + * Prepare attributes to remove fc-ports from forwarding-construct + ****************************************************************************************/ + + let forwardingConfigurationInputList = []; + let forwardingConstructConfigurationStatus; + let operationClientConfigurationStatusList = ltpConfigurationStatus.operationClientConfigurationStatusList; + + if (operationClientConfigurationStatusList) { + forwardingConfigurationInputList = await prepareForwardingConfiguration.disposeRemaindersOfDeregisteredApplication( + operationClientConfigurationStatusList + ); + forwardingConstructConfigurationStatus = await ForwardingConfigurationService. + unConfigureForwardingConstructAsync( + operationServerName, + forwardingConfigurationInputList + ); + } + + /**************************************************************************************** + * Prepare attributes to automate forwarding-construct + ****************************************************************************************/ + let forwardingAutomationInputList = await prepareForwardingAutomation.disposeRemaindersOfDeregisteredApplication( + ltpConfigurationStatus, + forwardingConstructConfigurationStatus + ); + ForwardingAutomationService.automateForwardingConstructAsync( + operationServerName, + forwardingAutomationInputList, + user, + xCorrelator, + traceIndicator, + customerJourney + ); +} /** * Embed yourself into the MBH SDN application layer @@ -54,12 +117,7 @@ exports.embedYourself = async function (body, user, xCorrelator, traceIndicator, let deregisterOperation = body["deregistration-operation"]; let relayOperationUpdateOperation = body["relay-operation-update-operation"]; let relayServerReplacementOperation = body["relay-server-replacement-operation"]; - - let oldReleaseProtocol = body["old-release-protocol"]; - let oldReleaseAddress = body["old-release-address"]; - let oldReleasePort = body["old-release-port"]; - - + const registryOfficeApplicationName = await ServiceUtils.resolveRegistryOfficeApplicationNameFromForwardingAsync(); if (registryOfficeApplicationName !== applicationName) { throw new createHttpError.BadRequest(`The registry-office-application ${applicationName} was not found.`); @@ -100,29 +158,48 @@ exports.embedYourself = async function (body, user, xCorrelator, traceIndicator, ltpConfigurationInput, isApplicationRo ); } + + /*********************************************************************** + * oldRelease information to be updated if provided in the requestBody + ***********************************************************************/ let isOldApplicationTcpClientUpdated = false; let oldApplicationTcpClientUuid; let oldApplicationForwardingTag = "PromptForEmbeddingCausesRequestForBequeathingData"; let isOldReleaseExist = await isForwardingNameExist(oldApplicationForwardingTag); let oldApplicationNameInConfiguration; + if (isOldReleaseExist) { let httpUuidOfOldApplication = await httpClientInterface.getHttpClientUuidFromForwarding(oldApplicationForwardingTag); oldApplicationNameInConfiguration = await ServiceUtils.resolveApplicationNameFromForwardingAsync(oldApplicationForwardingTag); + if (httpUuidOfOldApplication != undefined) { let tcpClientUuidList = await LogicalTerminationPoint.getServerLtpListAsync(httpUuidOfOldApplication); + if (tcpClientUuidList != undefined) { oldApplicationTcpClientUuid = tcpClientUuidList[0]; let tcpClientProtocolOfOldApplication = await tcpClientInterface.getRemoteProtocolAsync(oldApplicationTcpClientUuid); - if (oldReleaseProtocol != tcpClientProtocolOfOldApplication) { + if ("old-release-protocol" in body) + { + let oldReleaseProtocol = body["old-release-protocol"]; + if(oldReleaseProtocol != tcpClientProtocolOfOldApplication) { isOldApplicationTcpClientUpdated = await tcpClientInterface.setRemoteProtocolAsync(oldApplicationTcpClientUuid, oldReleaseProtocol); } - let tcpClientAddressOfOldApplication = await tcpClientInterface.getRemoteAddressAsync(oldApplicationTcpClientUuid); - if (oldReleaseAddress != tcpClientAddressOfOldApplication) { + } + if ("old-release-address" in body) + { + let oldReleaseAddress = body["old-release-address"]; + let tcpClientAddressOfOldApplication = await tcpClientInterface.getRemoteAddressAsync(oldApplicationTcpClientUuid); + if (oldReleaseAddress != tcpClientAddressOfOldApplication) { isOldApplicationTcpClientUpdated = await tcpClientInterface.setRemoteAddressAsync(oldApplicationTcpClientUuid, oldReleaseAddress); } - let tcpClientPortOfOldApplication = await tcpClientInterface.getRemotePortAsync(oldApplicationTcpClientUuid); - if (oldReleasePort != tcpClientPortOfOldApplication) { - isOldApplicationTcpClientUpdated = await tcpClientInterface.setRemotePortAsync(oldApplicationTcpClientUuid, oldReleasePort); + } + if ("old-release-port" in body) + { + let oldReleasePort = body["old-release-port"]; + let tcpClientPortOfOldApplication = await tcpClientInterface.getRemotePortAsync(oldApplicationTcpClientUuid); + if (oldReleasePort != tcpClientPortOfOldApplication) { + isOldApplicationTcpClientUpdated = await tcpClientInterface.setRemotePortAsync(oldApplicationTcpClientUuid, oldReleasePort); + } } } } @@ -247,6 +324,33 @@ exports.informAboutApplicationInGenericRepresentation = async function (operatio }); } + +/** + * Provides name and number of the preceding release + * If there is no OldRelease for this application , then a hardcoded applicationName "OldRelease" will be sent to smooth the ApprovingApplicationCausesPreparingTheEmbedding.RequestForOldRelease + * @oldReleaseForwardingName {String|undefined} forwardingName to identify a oldRelease , if there is no oldRelease then "undefined" shall be sent as a value. + * returns inline_response_200_3 + **/ +exports.informAboutPrecedingRelease = async function (oldReleaseForwardingName) { + try { + let precedingApplicationInformation = {}; + + let oldApplicationNameAndReleaseNumber = await ServiceUtils.resolveApplicationNameAndReleaseNumberFromForwardingAsync( + oldReleaseForwardingName); + + if (oldApplicationNameAndReleaseNumber) { + precedingApplicationInformation.applicationName = oldApplicationNameAndReleaseNumber.applicationName; + precedingApplicationInformation.releaseNumber = oldApplicationNameAndReleaseNumber.releaseNumber; + } else { + precedingApplicationInformation.applicationName = "OldRelease"; + precedingApplicationInformation.releaseNumber = await HttpServerInterface.getReleaseNumberAsync(); + } + return onfAttributeFormatter.modifyJsonObjectKeysToKebabCase(precedingApplicationInformation); + } catch (error) { + console.log(error); + } +} + /** * Returns release history * @@ -270,6 +374,98 @@ exports.informAboutReleaseHistoryInGenericRepresentation = async function (opera }); } + +/** + * Receives information about where to ask for approval of BasicAuth requests + * + * body V1_inquirebasicauthapprovals_body + * user String User identifier from the system starting the service call + * xCorrelator String UUID for the service execution flow that allows to correlate requests and responses + * traceIndicator String Sequence of request numbers along the flow + * customerJourney String Holds information supporting customer’s journey to which the execution applies + * operationServerName String Holds information about the url + * newReleaseFwName String Holds information about the new release forwarding name if exist + * no response value expected for this operation + **/ +exports.inquireBasicAuthRequestApprovals = async function (body, user, xCorrelator, traceIndicator, customerJourney, operationServerName, newReleaseFwName) { + let applicationName = body["application-name"]; + let releaseNumber = body["release-number"]; + let applicationProtocol = body["protocol"]; + let applicationAddress = body["address"]; + let applicationPort = body["port"]; + let basicAuthApprovalOperation = body["operation-name"]; + + + let httpClientUuid = await httpClientInterface.getHttpClientUuidFromForwarding("BasicAuthRequestCausesInquiryForAuthentication"); + + let operationNamesByAttributes = new Map(); + operationNamesByAttributes.set("basic-auth-approval-operation", basicAuthApprovalOperation); + + let tcpObjectList = [new TcpObject(applicationProtocol, applicationAddress, applicationPort)]; + + if (!httpClientUuid) { + httpClientUuid = await httpClientInterface.getHttpClientUuidExcludingOldReleaseAndNewRelease( + applicationName, + undefined, + newReleaseFwName + ); + } + let ltpConfigurationInput = new LogicalTerminationPointConfigurationInput( + httpClientUuid, + applicationName, + releaseNumber, + tcpObjectList, + operationServerName, + operationNamesByAttributes, + basicServicesOperationsMapping.basicServicesOperationsMapping + ); + let ltpConfigurationStatus; + if (httpClientUuid) { + ltpConfigurationStatus = await LogicalTerminationPointService.createOrUpdateApplicationLtpsAsync( + ltpConfigurationInput, false + ); + } + + /**************************************************************************************** + * Prepare attributes to configure forwarding-construct + ****************************************************************************************/ + + let forwardingConfigurationInputList = []; + let forwardingConstructConfigurationStatus; + let operationClientConfigurationStatusList; + if (ltpConfigurationStatus) { + operationClientConfigurationStatusList = ltpConfigurationStatus.operationClientConfigurationStatusList; + } + + if (operationClientConfigurationStatusList) { + forwardingConfigurationInputList = await prepareForwardingConfiguration.inquireBasicAuthRequestApprovals( + operationClientConfigurationStatusList, + basicAuthApprovalOperation + ); + forwardingConstructConfigurationStatus = await ForwardingConfigurationService. + configureForwardingConstructAsync( + operationServerName, + forwardingConfigurationInputList + ); + } + + /**************************************************************************************** + * Prepare attributes to automate forwarding-construct + ****************************************************************************************/ + let forwardingAutomationInputList = await prepareForwardingAutomation.inquireBasicAuthRequestApprovals( + ltpConfigurationStatus, + forwardingConstructConfigurationStatus + ); + ForwardingAutomationService.automateForwardingConstructAsync( + operationServerName, + forwardingAutomationInputList, + user, + xCorrelator, + traceIndicator, + customerJourney + ); +} + /** * Receives information about where to ask for approval of OaM requests * @@ -818,9 +1014,6 @@ exports.registerYourself = async function (body, user, xCorrelator, traceIndicat let httpAddress = body["http-address"]; let httpPort = body["http-port"]; - let httpsAddress = body["https-address"]; - let httpsPort = body["https-port"]; - oldApplicationName = body["preceding-application-name"]; oldReleaseNumber = body["preceding-release-number"]; @@ -871,16 +1064,7 @@ exports.registerYourself = async function (body, user, xCorrelator, traceIndicat let tcpClientConfigurationStatusList = ltpConfigurationStatus.tcpClientConfigurationStatusList; tcpClientConfigurationStatusList.push(configurationStatus); } - } - - let tcpServerWithHttpsUpdated = await updateTcpServerDetails("HTTPS", httpsAddress, httpsPort); - if (tcpServerWithHttpsUpdated.istcpServerUpdated) { - let configurationStatus = new ConfigurationStatus(tcpServerWithHttpsUpdated.tcpServerUuid, '', tcpServerWithHttpsUpdated.istcpServerUpdated); - if (ltpConfigurationStatus) { - let tcpClientConfigurationStatusList = ltpConfigurationStatus.tcpClientConfigurationStatusList; - tcpClientConfigurationStatusList.push(configurationStatus); - } - } + } // update old release configuration let isOldApplicationIsUpdated = false; @@ -1080,6 +1264,97 @@ exports.updateClient = async function (body, user, xCorrelator, traceIndicator, ); } + +/** + * Configures Http and TcpClient of the NewRelease + * + * body V1_updateclientofsubsequentrelease_body + * user String User identifier from the system starting the service call + * originator String 'Identification for the system consuming the API, as defined in [/core-model-1-4:control-construct/logical-termination-point={uuid}/layer-protocol=0/http-client-interface-1-0:http-client-interface-pac/http-client-interface-configuration/application-name]' + * xCorrelator String UUID for the service execution flow that allows to correlate requests and responses + * traceIndicator String Sequence of request numbers along the flow + * customerJourney String Holds information supporting customer’s journey to which the execution applies + * returns inline_response_200_4 + **/ +exports.updateClientOfSubsequentRelease = async function (body, user, xCorrelator, traceIndicator, customerJourney, operationServerName, newReleaseForwardingName) { + let futureApplicationName = body["application-name"]; + let futureReleaseNumber = body["release-number"]; + let futureProtocol = body["protocol"]; + let futureAddress = body["address"]; + let futurePort = body["port"]; + + let bequeathYourDataAndDieOperation; + let dataTransferOperationsList = []; + /**************************************************************************************** + * Prepare logicalTerminatinPointConfigurationInput object to + * configure logical-termination-point + ****************************************************************************************/ + + let ltpConfigurationStatus = {}; + let newReleaseHttpClientLtpUuid = await httpClientInterface.getHttpClientUuidFromForwarding(newReleaseForwardingName); + if (newReleaseHttpClientLtpUuid != undefined) { + let isReleaseUpdated = await httpClientInterface.setReleaseNumberAsync(newReleaseHttpClientLtpUuid, futureReleaseNumber); + let isApplicationNameUpdated = await httpClientInterface.setApplicationNameAsync(newReleaseHttpClientLtpUuid, futureApplicationName); + + if (isReleaseUpdated || isApplicationNameUpdated) { + let configurationStatus = new ConfigurationStatus( + newReleaseHttpClientLtpUuid, + '', + true); + ltpConfigurationStatus.httpClientConfigurationStatus = configurationStatus; + } + + let newReleaseTcpClientUuidList = await LogicalTerminationPoint.getServerLtpListAsync(newReleaseHttpClientLtpUuid); + let newReleaseTcpClientUuid = newReleaseTcpClientUuidList[0]; + + let isProtocolUpdated = await tcpClientInterface.setRemoteProtocolAsync(newReleaseTcpClientUuid, futureProtocol); + let isAddressUpdated = await tcpClientInterface.setRemoteAddressAsync(newReleaseTcpClientUuid, futureAddress); + let isPortUpdated = await tcpClientInterface.setRemotePortAsync(newReleaseTcpClientUuid, futurePort); + + if (isProtocolUpdated || isAddressUpdated || isPortUpdated) { + let configurationStatus = new ConfigurationStatus( + newReleaseTcpClientUuid, + '', + true); + ltpConfigurationStatus.tcpClientConfigurationStatusList = [configurationStatus]; + } + let forwardingAutomationInputList; + if (ltpConfigurationStatus != undefined) { + + /**************************************************************************************** + * Prepare attributes to automate forwarding-construct + ****************************************************************************************/ + forwardingAutomationInputList = await prepareForwardingAutomation.updateClientOfSubsequentRelease( + ltpConfigurationStatus + ); + ForwardingAutomationService.automateForwardingConstructAsync( + operationServerName, + forwardingAutomationInputList, + user, + xCorrelator, + traceIndicator, + customerJourney + ); + } + } + + bequeathYourDataAndDieOperation = await operationServerInterface.getInputOperationServerNameFromForwarding(newReleaseForwardingName); + let dataTransferOperationClientUuidList = await LogicalTerminationPoint.getClientLtpListAsync(newReleaseHttpClientLtpUuid); + for (let i = 0; i < dataTransferOperationClientUuidList.length; i++) { + let operationClientUuid = dataTransferOperationClientUuidList[i]; + let operationClientName = await OperationClientInterface.getOperationNameAsync(operationClientUuid); + dataTransferOperationsList.push(operationClientName); + } + + /**************************************************************************************** + * Prepare attributes for the response body + ****************************************************************************************/ + var handOverAndDatatransferInformation = {}; + handOverAndDatatransferInformation.bequeathYourDataAndDieOperation = bequeathYourDataAndDieOperation; + handOverAndDatatransferInformation.dataTransferOperationsList = dataTransferOperationsList; + return onfAttributeFormatter.modifyJsonObjectKeysToKebabCase(handOverAndDatatransferInformation); +} + /** * Allows updating operation clients to redirect to backward compatible services * @@ -1142,25 +1417,14 @@ exports.updateOperationClient = async function (body, user, xCorrelator, traceIn exports.updateOperationKey = async function (body) { let operationUuid = body["operation-uuid"]; let newOperationKey = body["new-operation-key"]; - - if (await operationServerInterface.isOperationServerAsync(operationUuid)) { - let OldoperationKey = await operationServerInterface.getOperationKeyAsync(operationUuid) - if (OldoperationKey != undefined) { - if (newOperationKey != OldoperationKey) { - await operationServerInterface.setOperationKeyAsync(operationUuid, newOperationKey); - } - } else { - throw new createHttpError.BadRequest("OperationServerUuid is not present"); - } - } else if (await operationClientInterface.isOperationClientAsync(operationUuid)) { - let OldoperationKey = await operationClientInterface.getOperationKeyAsync(operationUuid) - if (OldoperationKey != undefined) { - if (newOperationKey != OldoperationKey) { - await operationClientInterface.setOperationKeyAsync(operationUuid, newOperationKey); - } - } else { - throw new createHttpError.BadRequest("OperationClientUuid is not present"); - } + let isOperationServerUuid = await operationServerInterface.isOperationServerAsync(operationUuid); + let isOperationClientUuid = await operationClientInterface.isOperationClientAsync(operationUuid); + if (isOperationServerUuid) { + operationServerInterface.setOperationKeyAsync(operationUuid, newOperationKey); + } else if (isOperationClientUuid) { + operationClientInterface.setOperationKeyAsync(operationUuid, newOperationKey); + }else { + throw new createHttpError.BadRequest("OperationClientUuid/OperationServerUuid is not present"); } } diff --git a/server/basicServices/basicServices/services/PrepareForwardingAutomation.js b/server/basicServices/basicServices/services/PrepareForwardingAutomation.js index 9327f558..b46afa1a 100644 --- a/server/basicServices/basicServices/services/PrepareForwardingAutomation.js +++ b/server/basicServices/basicServices/services/PrepareForwardingAutomation.js @@ -14,6 +14,33 @@ const forwardingConstructAutomationInput = require('onf-core-model-ap/applicatio const prepareALTForwardingAutomation = require('./PrepareALTForwardingAutomation'); const TcpClientInterface = require('onf-core-model-ap/applicationPattern/onfModel/models/layerProtocols/TcpClientInterface'); +exports.disposeRemaindersOfDeregisteredApplication = function (logicalTerminationPointconfigurationStatus, forwardingConstructConfigurationStatus) { + return new Promise(async function (resolve, reject) { + let forwardingConstructAutomationList = []; + try { + + /*********************************************************************************** + * forwardings for application layer topology + ************************************************************************************/ + let applicationLayerTopologyForwardingInputList = await prepareALTForwardingAutomation.getALTUnConfigureForwardingAutomationInputAsync( + logicalTerminationPointconfigurationStatus, + forwardingConstructConfigurationStatus + ); + + if (applicationLayerTopologyForwardingInputList) { + for (let i = 0; i < applicationLayerTopologyForwardingInputList.length; i++) { + let applicationLayerTopologyForwardingInput = applicationLayerTopologyForwardingInputList[i]; + forwardingConstructAutomationList.push(applicationLayerTopologyForwardingInput); + } + } + + resolve(forwardingConstructAutomationList); + } catch (error) { + reject(error); + } + }); +} + exports.embedYourself = function (logicalTerminationPointconfigurationStatus, forwardingConstructConfigurationStatus, oldApplicationName = '') { return new Promise(async function (resolve, reject) { let forwardingConstructAutomationList = []; @@ -137,6 +164,54 @@ exports.registerYourself = function (logicalTerminationPointconfigurationStatus, ); forwardingConstructAutomationList.push(forwardingAutomation); + /*********************************************************************************** + * PromptForRegisteringCausesRegistrationRequest2 /v2/register-application + ***********************************************************************************/ + let registrationRequest2ForwardingName = "PromptForRegisteringCausesRegistrationRequest2"; + let registrationRequest2Context; + let registrationRequest2RequestBody = {}; + let registrationRequest2TcpServerList = []; + registrationRequest2RequestBody.applicationName = await httpServerInterface.getApplicationNameAsync(); + registrationRequest2RequestBody.releaseNumber = await httpServerInterface.getReleaseNumberAsync(); + registrationRequest2RequestBody.embeddingOperation = await operationServerInterface.getOperationNameAsync(controlConstructUuid + "-op-s-bm-001"); + registrationRequest2RequestBody.clientUpdateOperation = await operationServerInterface.getOperationNameAsync(controlConstructUuid + "-op-s-bm-007"); + registrationRequest2RequestBody.operationClientUpdateOperation = await operationServerInterface.getOperationNameAsync(controlConstructUuid + "-op-s-bm-011"); + registrationRequest2RequestBody.disposeRemaindersOperation = await operationServerInterface.getOperationNameAsync(controlConstructUuid + "-op-s-bm-013"); + registrationRequest2RequestBody.precedingReleaseOperation = await operationServerInterface.getOperationNameAsync(controlConstructUuid + "-op-s-bm-014"); + registrationRequest2RequestBody.subsequentReleaseOperation = await operationServerInterface.getOperationNameAsync(controlConstructUuid + "-op-s-bm-015"); + + // formulate the tcp-server-list + let registrationRequest2TcpHttpAddress = await tcpServerInterface.getLocalAddressOfTheProtocol("HTTP"); + let registrationRequest2TcpHttpPort = await tcpServerInterface.getLocalPortOfTheProtocol("HTTP"); + if (registrationRequest2TcpHttpAddress != undefined && registrationRequest2TcpHttpPort != undefined) { + if ("ipv-4-address" in registrationRequest2TcpHttpAddress) { + registrationRequest2TcpHttpAddress = { + "ip-address": registrationRequest2TcpHttpAddress + } + } + let registrationRequest2tcpServer = { + protocol: "HTTP", + port: registrationRequest2TcpHttpPort, + address: registrationRequest2TcpHttpAddress + } + registrationRequest2TcpServerList.push(registrationRequest2tcpServer); + } + + registrationRequest2RequestBody.tcpServerList = registrationRequest2TcpServerList; + if (oldApplicationName) { + registrationRequest2RequestBody.precedingApplicationName = oldApplicationName; + } + if (oldReleaseNumber) { + registrationRequest2RequestBody.precedingReleaseNumber = oldReleaseNumber; + } + registrationRequest2RequestBody = onfFormatter.modifyJsonObjectKeysToKebabCase(registrationRequest2RequestBody); + let registrationRequest2forwardingAutomation = new forwardingConstructAutomationInput( + registrationRequest2ForwardingName, + registrationRequest2RequestBody, + registrationRequest2Context + ); + forwardingConstructAutomationList.push(registrationRequest2forwardingAutomation); + /*********************************************************************************** * forwardings for application layer topology ************************************************************************************/ @@ -165,6 +240,33 @@ exports.endSubscription = function (forwardingConstructConfigurationStatus) { ); } +exports.inquireBasicAuthRequestApprovals = function (logicalTerminationPointconfigurationStatus, forwardingConstructConfigurationStatus) { + return new Promise(async function (resolve, reject) { + let forwardingConstructAutomationList = []; + try { + + /*********************************************************************************** + * forwardings for application layer topology + ************************************************************************************/ + let applicationLayerTopologyForwardingInputList = await prepareALTForwardingAutomation.getALTForwardingAutomationInputAsync( + logicalTerminationPointconfigurationStatus, + forwardingConstructConfigurationStatus + ); + + if (applicationLayerTopologyForwardingInputList) { + for (let i = 0; i < applicationLayerTopologyForwardingInputList.length; i++) { + let applicationLayerTopologyForwardingInput = applicationLayerTopologyForwardingInputList[i]; + forwardingConstructAutomationList.push(applicationLayerTopologyForwardingInput); + } + } + + resolve(forwardingConstructAutomationList); + } catch (error) { + reject(error); + } + }); +} + exports.inquireOamRequestApprovals = function (logicalTerminationPointconfigurationStatus, forwardingConstructConfigurationStatus) { return new Promise(async function (resolve, reject) { let forwardingConstructAutomationList = []; @@ -361,6 +463,33 @@ exports.updateClient = function (logicalTerminationPointconfigurationStatus, for }); } +exports.updateClientOfSubsequentRelease = function (logicalTerminationPointconfigurationStatus, forwardingConstructConfigurationStatus) { + return new Promise(async function (resolve, reject) { + let forwardingConstructAutomationList = []; + try { + + /*********************************************************************************** + * forwardings for application layer topology + ************************************************************************************/ + let applicationLayerTopologyForwardingInputList = await prepareALTForwardingAutomation.getALTForwardingAutomationInputAsync( + logicalTerminationPointconfigurationStatus, + forwardingConstructConfigurationStatus + ); + + if (applicationLayerTopologyForwardingInputList) { + for (let i = 0; i < applicationLayerTopologyForwardingInputList.length; i++) { + let applicationLayerTopologyForwardingInput = applicationLayerTopologyForwardingInputList[i]; + forwardingConstructAutomationList.push(applicationLayerTopologyForwardingInput); + } + } + + resolve(forwardingConstructAutomationList); + } catch (error) { + reject(error); + } + }); +} + function isLifeCycleStateDeprecated(lifeCycleState) { let deprecatedLifeCycleState = operationServerInterface.OperationServerInterfacePac.OperationServerInterfaceConfiguration.lifeCycleStateEnum.DEPRECATED let lifeCycleStateEnum = operationServerInterface.OperationServerInterfacePac.OperationServerInterfaceConfiguration.lifeCycleStateEnum; diff --git a/server/basicServices/basicServices/services/PrepareForwardingConfiguration.js b/server/basicServices/basicServices/services/PrepareForwardingConfiguration.js index 9a0f7a6a..253a0b0e 100644 --- a/server/basicServices/basicServices/services/PrepareForwardingConfiguration.js +++ b/server/basicServices/basicServices/services/PrepareForwardingConfiguration.js @@ -8,6 +8,38 @@ const logicalTerminationPoint = require('onf-core-model-ap/applicationPattern/on +exports.disposeRemaindersOfDeregisteredApplication = function (operationClientConfigurationStatusList) { + return new Promise(async function (resolve, reject) { + let forwardingConfigurationInputList = []; + try { + for (let i = 0; i < operationClientConfigurationStatusList.length; i++) { + + let configurationStatus = operationClientConfigurationStatusList[i]; + let operationClientUuid = configurationStatus.uuid; + + let forwardingConstructList = await forwardingDomain.getForwardingConstructListForTheFcPortAsync( + operationClientUuid, + FcPort.portDirectionEnum.OUTPUT); + + for (let j = 0; j < forwardingConstructList.length; j++) { + let fcNameList = forwardingConstructList[j]["name"]; + let forwardingName = getValueFromKey(fcNameList, "ForwardingName"); + let forwardingConfigurationInput = new forwardingConstructConfigurationInput( + forwardingName, + operationClientUuid + ); + forwardingConfigurationInputList.push( + forwardingConfigurationInput + ); + } + } + resolve(forwardingConfigurationInputList); + } catch (error) { + reject(error); + } + }); +} + exports.embedYourself = function (operationClientConfigurationStatusList, deregisterOperation, relayServerReplacementOperation, relayOperationUpdateOperation) { return new Promise(async function (resolve, reject) { let forwardingConfigurationInputList = []; @@ -83,6 +115,36 @@ exports.registerYourself = function (operationClientConfigurationStatusList, reg } +exports.inquireBasicAuthRequestApprovals = function (operationClientConfigurationStatusList, basicAuthApprovalOperation) { + return new Promise(async function (resolve, reject) { + let forwardingConfigurationInputList = []; + try { + for (let i = 0; i < operationClientConfigurationStatusList.length; i++) { + let configurationStatus = operationClientConfigurationStatusList[i]; + let operationClientUuid = configurationStatus.uuid; + let operationClientName = await operationClientInterface. + getOperationNameAsync(operationClientUuid); + let forwardingConfigurationInput; + let forwardingName; + if (operationClientName == basicAuthApprovalOperation) { + forwardingName = + "BasicAuthRequestCausesInquiryForAuthentication"; + forwardingConfigurationInput = new forwardingConstructConfigurationInput( + forwardingName, + operationClientUuid + ); + } + forwardingConfigurationInputList.push( + forwardingConfigurationInput + ); + } + resolve(forwardingConfigurationInputList); + } catch (error) { + reject(error); + } + }); +} + exports.inquireOamRequestApprovals = function (operationClientConfigurationStatusList, oamApprovalOperation) { return new Promise(async function (resolve, reject) { let forwardingConfigurationInputList = []; diff --git a/server/basicServices/basicServices/utility/LogicalTerminationPoint.js b/server/basicServices/basicServices/utility/LogicalTerminationPoint.js index 57406613..ba24dec3 100644 --- a/server/basicServices/basicServices/utility/LogicalTerminationPoint.js +++ b/server/basicServices/basicServices/utility/LogicalTerminationPoint.js @@ -96,6 +96,30 @@ exports.resolveApplicationNameFromForwardingAsync = async function (forwardingNa return await httpClientInterface.getApplicationNameAsync(httpLtpUuidList[0]); } +/** + * Resolves application name and release number from the forwarding name. + * @param {String} forwardingName + * @returns {Promise} application name and release number + */ +exports.resolveApplicationNameAndReleaseNumberFromForwardingAsync = async function (forwardingName) { + const forwardingConstruct = await ForwardingDomain.getForwardingConstructForTheForwardingNameAsync(forwardingName); + if (forwardingConstruct === undefined) { + return undefined; + } + const fcPortList = forwardingConstruct[onfAttributes.FORWARDING_CONSTRUCT.FC_PORT]; + const roFcPort = fcPortList.find(fcPort => + FcPort.portDirectionEnum.OUTPUT === fcPort[onfAttributes.FC_PORT.PORT_DIRECTION] + ); + const httpLtpUuidList = await LogicalTerminationPoint.getServerLtpListAsync(roFcPort[onfAttributes.FC_PORT.LOGICAL_TERMINATION_POINT]); + let applicationName = await httpClientInterface.getApplicationNameAsync(httpLtpUuidList[0]); + let releaseNumber = await httpClientInterface.getReleaseNumberAsync(httpLtpUuidList[0]); + let result = { + "applicationName" : applicationName, + "releaseNumber" : releaseNumber + }; + return result; +} + /** * Resolves registry office application name from forwarding name : "PromptForRegisteringCausesRegistrationRequest". * @returns {Promise} application name