From 3d02271058d2e59a71e49afdd866462f7b6ab1c6 Mon Sep 17 00:00:00 2001 From: Aijana Schumann Date: Wed, 12 Aug 2020 12:28:06 +0200 Subject: Switch odlux from Biermann-RestConf to RFC8040 interface Switched rest-calls in odlux to use RFC8040 interface Issue-ID: CCSDK-2565 Signed-off-by: Aijana Schumann Change-Id: Ia59dd02bc6456bad648083146c0256f204e134d1 --- .../configurationApp/src/actions/deviceActions.ts | 46 ++++++++++++++-------- .../configurationApp/src/services/restServices.ts | 20 +++++----- .../odlux/apps/configurationApp/webpack.config.js | 35 ++++++++++------ 3 files changed, 63 insertions(+), 38 deletions(-) (limited to 'sdnr/wt/odlux/apps/configurationApp') diff --git a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts index dbe95e0d1..1db66c0d4 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/actions/deviceActions.ts @@ -89,7 +89,8 @@ export const splitVPath = (vPath: string, vPathParser : RegExp): [string, string const getReferencedDataList = async (refPath: string, dataPath: string, modules: { [name: string]: Module }, views: ViewSpecification[]) => { const pathParts = splitVPath(refPath, /(?:(?:([^\/\:]+):)?([^\/]+))/g); // 1 = opt: namespace / 2 = property - let referencedModule = modules[pathParts[0][0]]; + const defaultNS = pathParts[0][0]; + let referencedModule = modules[defaultNS]; let dataMember: string; let view: ViewSpecification; @@ -121,14 +122,17 @@ const getReferencedDataList = async (refPath: string, dataPath: string, modules: throw new Error(`Server Error. Status: [${restResult.status}]\n${message || restResult.message || ''}`); } - let dataRaw = restResult.data[dataMember!]; + let dataRaw = restResult.data[`${defaultNS}:${dataMember!}`]; + if (dataRaw === undefined) { + dataRaw = restResult.data[dataMember!]; + } dataRaw = dataRaw instanceof Array ? dataRaw[0] : dataRaw; data = dataRaw && dataRaw[viewElement.label] || []; const keys: string[] = data.map((entry: { [key: string]: any } )=> entry[viewElement.key!]); - resultingDataUrls.push(...keys.map(key => `${dataUrl}/${viewElement.label.replace(/\//ig, "%2F")}/${key.replace(/\//ig, "%2F")}`)); + resultingDataUrls.push(...keys.map(key => `${dataUrl}/${viewElement.label.replace(/\//ig, "%2F")}=${key.replace(/\//ig, "%2F")}`)); } dataMember = viewElement.label; } else { @@ -149,7 +153,10 @@ const getReferencedDataList = async (refPath: string, dataPath: string, modules: const message = restResult.data && restResult.data.errors && restResult.data.errors.error && restResult.data.errors.error[0] && restResult.data.errors.error[0]["error-message"] || ""; throw new Error(`Server Error. Status: [${restResult.status}]\n${message || restResult.message || ''}`); } - let dataRaw = restResult.data[dataMember!]; + let dataRaw = restResult.data[`${defaultNS}:${dataMember!}`]; + if (dataRaw === undefined) { + dataRaw = restResult.data[dataMember!]; + } dataRaw = dataRaw instanceof Array ? dataRaw[0] : dataRaw; @@ -227,7 +234,7 @@ const flatenViewElements = (defaultNS: string | null, parentPath: string, elemen export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key const { configuration: { deviceDescription: { nodeId, modules, views } }, framework: { navigationState } } = getState(); - let dataPath = `/restconf/config/network-topology:network-topology/topology/topology-netconf/node/${nodeId}/yang-ext:mount`; + let dataPath = `/rests/data/network-topology:network-topology/topology=topology-netconf/node=${nodeId}/yang-ext:mount`; let inputViewSpecification: ViewSpecification | undefined = undefined; let outputViewSpecification: ViewSpecification | undefined = undefined; @@ -302,7 +309,11 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: } extractList = true; } else { - dataPath += `/${property}${key ? `/${key.replace(/\//ig, "%2F")}` : ""}`; + // normal case + dataPath += `/${property}${key ? `=${key.replace(/\//ig, "%2F")}` : ""}`; + + // in case of the root element the required namespace will be added later, + // while extracting the data dataMember = namespace === defaultNS ? viewElement.label : `${namespace}:${viewElement.label}`; @@ -352,7 +363,11 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: const message = restResult.data.errors && restResult.data.errors.error && restResult.data.errors.error[0] && restResult.data.errors.error[0]["error-message"] || ""; throw new Error(`Server Error. Status: [${restResult.status}]\n${message}`); } else { - data = restResult.data[dataMember!]; // extract dataMember + // https://tools.ietf.org/html/rfc7951#section-4 the root element may countain a namesapce or not ! + data = restResult.data[`${defaultNS}:${dataMember!}`]; + if (data === undefined) { + data = restResult.data[dataMember!]; // extract dataMember w/o namespace + } } // extract the first element list[key] @@ -405,7 +420,7 @@ export const updateViewActionAsyncCreator = (vPath: string) => async (dispatch: export const updateDataActionAsyncCreator = (vPath: string, data: any) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key const { configuration: { deviceDescription: { nodeId, views } } } = getState(); - let dataPath = `/restconf/config/network-topology:network-topology/topology/topology-netconf/node/${nodeId}/yang-ext:mount`; + let dataPath = `/rests/data/network-topology:network-topology/topology=topology-netconf/node=${nodeId}/yang-ext:mount`; let viewSpecification: ViewSpecification = views[0]; let viewElement: ViewElement; let dataMember: string; @@ -445,7 +460,7 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async } } - dataPath += `/${property}${key ? `/${key.replace(/\//ig, "%2F")}` : ""}`; + dataPath += `/${property}${key ? `=${key.replace(/\//ig, "%2F")}` : ""}`; dataMember = viewElement.label; embedList = false; @@ -466,7 +481,7 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async // do not extract root member (0) if (viewSpecification && viewSpecification.id !== "0") { - const updateResult = await restService.setConfigData(dataPath, { [dataMember!]: data }); // extractDataMember + const updateResult = await restService.setConfigData(dataPath, { [`${defaultNS}:${dataMember!}`]: data }); // addDataMember using defaultNS if (updateResult.status < 200 || updateResult.status > 299) { const message = updateResult.data && updateResult.data.errors && updateResult.data.errors.error && updateResult.data.errors.error[0] && updateResult.data.errors.error[0]["error-message"] || ""; throw new Error(`Server Error. Status: [${updateResult.status}]\n${message || updateResult.message || ''}`); @@ -499,7 +514,7 @@ export const updateDataActionAsyncCreator = (vPath: string, data: any) => async export const removeElementActionAsyncCreator = (vPath: string) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key const { configuration: { deviceDescription: { nodeId, views } } } = getState(); - let dataPath = `/restconf/config/network-topology:network-topology/topology/topology-netconf/node/${nodeId}/yang-ext:mount`; + let dataPath = `/rests/data/network-topology:network-topology/topology=topology-netconf/node=${nodeId}/yang-ext:mount`; let viewSpecification: ViewSpecification = views[0]; let viewElement: ViewElement; @@ -529,7 +544,7 @@ export const removeElementActionAsyncCreator = (vPath: string) => async (dispatc } } - dataPath += `/${property}${key ? `/${key.replace(/\//ig, "%2F")}` : ""}`; + dataPath += `/${property}${key ? `=${key.replace(/\//ig, "%2F")}` : ""}`; if (viewElement && "viewId" in viewElement) { viewSpecification = views[+viewElement.viewId]; @@ -555,7 +570,7 @@ export const removeElementActionAsyncCreator = (vPath: string) => async (dispatc export const executeRpcActionAsyncCreator = (vPath: string, data: any) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { const pathParts = splitVPath(vPath, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key const { configuration: { deviceDescription: { nodeId, views }, viewDescription: oldViewDescription } } = getState(); - let dataPath = `/restconf/operations/network-topology:network-topology/topology/topology-netconf/node/${nodeId}/yang-ext:mount`; + let dataPath = `/rests/operations/network-topology:network-topology/topology=topology-netconf/node=${nodeId}/yang-ext:mount`; let viewSpecification: ViewSpecification = views[0]; let viewElement: ViewElement; let dataMember: string; @@ -595,7 +610,7 @@ export const executeRpcActionAsyncCreator = (vPath: string, data: any) => async // } } - dataPath += `/${property}${key ? `/${key.replace(/\//ig, "%2F")}` : ""}`; + dataPath += `/${property}${key ? `=${key.replace(/\//ig, "%2F")}` : ""}`; dataMember = viewElement.label; embedList = false; @@ -637,8 +652,7 @@ export const executeRpcActionAsyncCreator = (vPath: string, data: any) => async const message = updateResult.data && updateResult.data.errors && updateResult.data.errors.error && updateResult.data.errors.error[0] && updateResult.data.errors.error[0]["error-message"] || ""; throw new Error(`Server Error. Status: [${updateResult.status}]\n${message || updateResult.message || ''}`); } - const viewData = { ...oldViewDescription.viewData, output: updateResult.data || null}; - dispatch(new UpdatOutputData(viewData)); + dispatch(new UpdatOutputData(updateResult.data)); } else { throw new Error(`There is NO RPC specified.`); } diff --git a/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts b/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts index b260f1ffb..eb2c67c26 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/services/restServices.ts @@ -23,10 +23,10 @@ import { NetworkElementConnection } from "../models/networkElementConnection"; class RestService { public async getCapabilitiesByMoutId(nodeId: string): Promise<{ "capabilityOrigin": string, "capability": string }[] | null> { - const path = `/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/${nodeId}`; - const capabilitiesResult = await requestRest<{ node: { "node-id": string, "netconf-node-topology:available-capabilities": { "available-capability": { "capabilityOrigin": string, "capability": string }[] }}[] }>(path, { method: "GET" }); - return capabilitiesResult && capabilitiesResult.node && capabilitiesResult.node.length > 0 && - capabilitiesResult.node[0]["netconf-node-topology:available-capabilities"]["available-capability"].map(obj => convertPropertyNames(obj, replaceHyphen)) || null; + const path = `/rests/data/network-topology:network-topology/topology=topology-netconf/node=${nodeId}`; + const capabilitiesResult = await requestRest<{"network-topology:node": {"node-id": string, "netconf-node-topology:available-capabilities": { "available-capability": { "capability-origin": string, "capability": string }[] }}[] }>(path, { method: "GET" }); + return capabilitiesResult && capabilitiesResult["network-topology:node"] && capabilitiesResult["network-topology:node"].length > 0 && + capabilitiesResult["network-topology:node"][0]["netconf-node-topology:available-capabilities"]["available-capability"].map(obj => convertPropertyNames(obj, replaceHyphen)) || null; } public async getMountedNetworkElementByMountId(nodeId: string): Promise { @@ -34,13 +34,13 @@ class RestService { // const connectedNetworkElement = await requestRest(path, { method: "GET" }); // return connectedNetworkElement || null; - const path = "/restconf/operations/data-provider:read-network-element-connection-list"; - const body = { "input": { "filter": [{ "property": "node-id", "filtervalue": nodeId }], "sortorder": [], "pagination": { "size": 1, "page": 1 } } }; - const networkElementResult = await requestRest<{ output: { data: NetworkElementConnection[] } }>(path, { method: "POST", body: JSON.stringify(body) }); - return networkElementResult && networkElementResult.output && networkElementResult.output.data && - networkElementResult.output.data.map(obj => convertPropertyNames(obj, replaceHyphen))[0] || null; + const path = "/rests/operations/data-provider:read-network-element-connection-list"; + const body = { "data-provider:input": { "filter": [{ "property": "node-id", "filtervalue": nodeId }], "sortorder": [], "pagination": { "size": 1, "page": 1 } } }; + const networkElementResult = await requestRest<{ "data-provider:output": { data: NetworkElementConnection[] } }>(path, { method: "POST", body: JSON.stringify(body) }); + return networkElementResult && networkElementResult["data-provider:output"] && networkElementResult["data-provider:output"].data && + networkElementResult["data-provider:output"].data.map(obj => convertPropertyNames(obj, replaceHyphen))[0] || null; } - + /** Reads the config data by restconf path. * @param path The restconf path to be used for read. * @returns The data. diff --git a/sdnr/wt/odlux/apps/configurationApp/webpack.config.js b/sdnr/wt/odlux/apps/configurationApp/webpack.config.js index dccf34919..329eb00f4 100644 --- a/sdnr/wt/odlux/apps/configurationApp/webpack.config.js +++ b/sdnr/wt/odlux/apps/configurationApp/webpack.config.js @@ -107,8 +107,11 @@ module.exports = (env) => { ] ], + watchOptions: { + ignored: /node_modules/ + }, + devServer: { - public: "http://localhost:3100", contentBase: frameworkPath, compress: true, @@ -125,31 +128,39 @@ module.exports = (env) => { stats: { colors: true }, - proxy: { - "/oauth2/": { - target: "http://localhost:48181", - secure: false - }, + proxy: { "/yang-schema/": { - target: "http://localhost:48181", + target: "http://10.20.6.29:48181", + secure: false + }, + "/oauth2/": { + target: "http://10.20.6.29:48181", secure: false }, "/database/": { - target: "http://localhost:48181", + target: "http://10.20.6.29:48181", secure: false }, "/restconf/": { - target: "http://localhost:48181", + target: "http://10.20.6.29:48181", + secure: false + }, + "/rests/": { + target: "http://10.20.6.29:48181", secure: false }, "/help/": { - target: "http://localhost:48181", + target: "http://10.20.6.29:48181", + secure: false + }, + "/tree/": { + target: "http://10.20.6.29:48181", secure: false }, "/websocket": { - target: "http://localhost:48181", + target: "http://10.20.6.29:48181", ws: true, - changeOrigin: false, + changeOrigin: true, secure: false } } -- cgit 1.2.3-korg