Include distribution artifacts 56/14556/1
authorRavi Pendurty <ravi.pendurty@highstreet-technologies.com>
Thu, 12 Jun 2025 10:23:13 +0000 (15:53 +0530)
committerRavi Pendurty <ravi.pendurty@highstreet-technologies.com>
Thu, 12 Jun 2025 10:23:13 +0000 (15:53 +0530)
Provides infrastucture for building sdnc-image and sdnc-web-image

Issue-ID: OAM-469
Change-Id: Ic97d9c208c38c4c4c934a7bf608ae6a0fd001148
Signed-off-by: Ravi Pendurty <ravi.pendurty@highstreet-technologies.com>
29 files changed:
distribution/TagVersion.groovy [new file with mode: 0644]
distribution/oam-controller-web/README.md [new file with mode: 0644]
distribution/oam-controller-web/certs/cacert.pem [new file with mode: 0644]
distribution/oam-controller-web/certs/cert.pem [new file with mode: 0644]
distribution/oam-controller-web/certs/key.pem [new file with mode: 0644]
distribution/oam-controller-web/pom.xml [new file with mode: 0644]
distribution/oam-controller-web/src/main/docker/Dockerfile [new file with mode: 0644]
distribution/oam-controller-web/src/main/resources/favicon.ico [new file with mode: 0644]
distribution/oam-controller-web/src/main/resources/http_custom.conf [new file with mode: 0644]
distribution/oam-controller-web/src/main/resources/http_site.conf [new file with mode: 0644]
distribution/oam-controller-web/src/main/resources/https_site.conf [new file with mode: 0644]
distribution/oam-controller-web/src/main/resources/location.rules [new file with mode: 0644]
distribution/oam-controller-web/src/main/resources/odlux.application.list [new file with mode: 0644]
distribution/oam-controller-web/src/main/scripts/configure.py [new file with mode: 0644]
distribution/oam-controller-web/src/main/scripts/core.py [new file with mode: 0644]
distribution/oam-controller-web/src/main/scripts/opm.py [new file with mode: 0755]
distribution/oam-controller-web/src/main/scripts/run.sh [new file with mode: 0644]
distribution/oam-controller/README.md [new file with mode: 0644]
distribution/oam-controller/certs/certs.properties [new file with mode: 0644]
distribution/oam-controller/certs/keys0.zip [new file with mode: 0644]
distribution/oam-controller/certs/keys1.zip [new file with mode: 0644]
distribution/oam-controller/pom.xml [new file with mode: 0644]
distribution/oam-controller/src/main/docker/Dockerfile [new file with mode: 0644]
distribution/oam-controller/src/main/etc/oauth-aaa-app-config.xml [new file with mode: 0644]
distribution/oam-controller/src/main/etc/oauth-provider.config.json [new file with mode: 0644]
distribution/oam-controller/src/main/etc/org.apache.karaf.management.cfg [new file with mode: 0644]
distribution/oam-controller/src/main/groovy/TagVersion.groovy [new file with mode: 0644]
distribution/oam-controller/src/main/scripts/installCerts.py [new file with mode: 0755]
distribution/oam-controller/src/main/scripts/startODL.sh [new file with mode: 0755]

diff --git a/distribution/TagVersion.groovy b/distribution/TagVersion.groovy
new file mode 100644 (file)
index 0000000..bcf2452
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CCSDK
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.sdnc.oam
+
+
+def versionArray;
+if ( project.properties['sdnc.project.version'] != null ) {
+       versionArray = project.properties['sdnc.project.version'].split('\\.');
+}
+
+if ( project.properties['sdnc.project.version'].endsWith("-SNAPSHOT") ) {
+       patchArray = versionArray[2].split('-');
+       project.properties['project.docker.latestminortag.version']=versionArray[0] + '.' + versionArray[1] + "-SNAPSHOT-latest";
+       project.properties['project.docker.latestfulltag.version']=versionArray[0] + '.' + versionArray[1] + '.' + patchArray[0] + "-SNAPSHOT-latest";
+       project.properties['project.docker.latesttagtimestamp.version']=versionArray[0] + '.' + versionArray[1] + '.' + patchArray[0] + "-SNAPSHOT-"+project.properties['sdnc.build.timestamp'];
+} else {
+       project.properties['project.docker.latestminortag.version']=versionArray[0] + '.' + versionArray[1] + "-STAGING-latest";
+       project.properties['project.docker.latestfulltag.version']=versionArray[0] + '.' + versionArray[1] + '.' + versionArray[2] + "-STAGING-latest";
+       project.properties['project.docker.latesttagtimestamp.version']=versionArray[0] + '.' + versionArray[1] + '.' + versionArray[2] + "-STAGING-"+project.properties['sdnc.build.timestamp'];
+}
diff --git a/distribution/oam-controller-web/README.md b/distribution/oam-controller-web/README.md
new file mode 100644 (file)
index 0000000..834b93a
--- /dev/null
@@ -0,0 +1,56 @@
+# sdnc web image
+
+
+## folder structure
+
+| folder | description |
+| ------ | ----------- |
+| /opt/bitnami/nginx/conf/server_blocks/http(s)_site.conf | nginx config |
+| /opt/bitnami/nginx/conf/server_blocks/location.rules | forwarding rules for nginx |
+| /app/odlux | http content files (html, js, css, ...) |
+| /app/odlux.application.list | application list file |
+| /app/opm.py | Odlux package manager for install or uninstall apps |
+| /app/init.d/ | autoinstall folder for opm |
+
+## Default app order
+
+| index | application |
+| ----- | ----------- |
+| 1 | connectApp |
+| 10 | faultApp |
+| 20 | maintenanceApp |
+| 30 | configurationApp |
+| 55 | performanceHistoryApp |
+| 70 | inventoryApp |
+| 75 | eventLogApp |
+| 90 | mediatorApp |
+| 200 | helpApp |
+
+
+## usage
+
+### auto installation
+
+To auto install additional applications for odlux they can be easily injected before startup into the ```/app/init.d/``` folder. There are two options of file format allowed.
+
+[1] The first fileformat is e.g. 55microwaveApp.jar but also .zip is allowed. The important thing is that a number is leading the app package to specify the order number where the menu item is ordered in the menu bar. So the microwaveApp would be located between performanceApp and inventoryApp.
+
+[2] The second is the default jar format, like it would be installed into the opendaylight karaf environment, including a blueprint and the sources. There the filename is not important because application name and index will be detected by the blueprint information.
+
+
+### manual method
+```
+opm install --name myApp --index 53 --file myarchive.zip
+```
+```
+opm install --url https://link-to-my-odlux-application.jar
+```
+
+```
+opm uninstall --name myApp
+```
+
+```
+opm list
+```
+
diff --git a/distribution/oam-controller-web/certs/cacert.pem b/distribution/oam-controller-web/certs/cacert.pem
new file mode 100644 (file)
index 0000000..0146e6b
--- /dev/null
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFPjCCAyagAwIBAgIJAJ6u7cCnzrWdMA0GCSqGSIb3DQEBCwUAMCwxDjAMBgNV\r
+BAsMBU9TQUFGMQ0wCwYDVQQKDARPTkFQMQswCQYDVQQGEwJVUzAeFw0xODA0MDUx\r
+NDE1MjhaFw0zODAzMzExNDE1MjhaMCwxDjAMBgNVBAsMBU9TQUFGMQ0wCwYDVQQK\r
+DARPTkFQMQswCQYDVQQGEwJVUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\r
+ggIBAMA5pkgRs7NhGG4ew5JouhyYakgYUyFaG121+/h8qbSdt0hVQv56+EA41Yq7\r
+XGie7RYDQK9NmAFF3gruE+6X7wvJiChp+Cyd7sFMnb65uWhxEdxWTM2BJFrgfzUn\r
+H8ZCxgaCo3XH4PzlKRy2LQQJEJECwl/RZmRCXijMt5e9h8XoZY/fKkKcZZUsWNCM\r
+pTo266wjvA9MXLmdgReRj0+vrCjrNqy+htwJDztoiHWiYPqT6o8EvGcgjNqjlZx7\r
+NUNf8MfLDByqKF6+wRbHv1GKjn3/Vijd45Fv8riyRYROiFanvbV6jIfBkv8PZbXg\r
+2VDWsYsgp8NAvMxK+iV8cO+Ck3lBI2GOPZbCEqpPVTYbLUz6sczAlCXwQoPzDIZY\r
+wYa3eR/gYLY1gP2iEVHORag3bLPap9ZX5E8DZkzTNTjovvLk8KaCmfcaUMJsBtDd\r
+ApcUitz10cnRyZc1sX3gE1f3DpzQM6t9C5sOVyRhDcSrKqqwb9m0Ss04XAS9FsqM\r
+P3UWYQyqDXSxlUAYaX892u8mV1hxnt2gjb22RloXMM6TovM3sSrJS0wH+l1nznd6\r
+aFXftS/G4ZVIVZ/LfT1is4StoyPWZCwwwly1z8qJQ/zhip5NgZTxQw4mi7ww35DY\r
+PdAQOCoajfSvFjqslQ/cPRi/MRCu079heVb5fQnnzVtnpFQRAgMBAAGjYzBhMB0G\r
+A1UdDgQWBBRTVTPyS+vQUbHBeJrBKDF77+rtSTAfBgNVHSMEGDAWgBRTVTPyS+vQ\r
+UbHBeJrBKDF77+rtSTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAN\r
+BgkqhkiG9w0BAQsFAAOCAgEAPx/IaK94n02wPxpnYTy+LVLIxwdq/kawNd6IbiMz\r
+L87zmNMDmHcGbfoRCj8OkhuggX9Lx1/CkhpXimuYsZOFQi5blr/u+v4mIbsgbmi9\r
+7j+cUHDP0zLycvSvxKHty51LwmaX9a4wkJl5zBU4O1sd/H9tWcEmwJ39ltKoBKBx\r
+c94Zc3iMm5ytRWGj+0rKzLDAXEWpoZ5bE5PLJauA6UDCxDLfs3FwhbS7uDggxYvf\r
+jySF5FCNET94oJ+m8s7VeHvoa8iPGKvXrIqdd7XDHnqJJlVKr7m9S0fMbyEB8ci2\r
+RtOXDt93ifY1uhoEtEykn4dqBSp8ezvNMnwoXdYPDvTd9uCAFeWFLVreBAWxd25h\r
+PsBTkZA5hpa/rA+mKv6Af4VBViYr8cz4dZCsFChuioVebe9ighrfjB//qKepFjPF\r
+CyjzKN1u0JKm/2x/ORqxkTONG8p3uDwoIOyimUcTtTMv42bfYD88RKakqSFXE9G+\r
+Z0LlaKABqfjK49o/tsAp+c5LoNlYllKhnetO3QAdraHwdmC36BhoghzR1jpX751A\r
+cZn2VH3Q4XKyp01cJNCJIrua+A+bx6zh3RyW6zIIkbRCbET+UD+4mr8WIcSE3mtR\r
+ZVlnhUDO4z9//WKMVzwS9Rh8/kuszrGFI1KQozXCHLrce3YP6RYZfOed79LXaRwX\r
+dYY=
+-----END CERTIFICATE-----
diff --git a/distribution/oam-controller-web/certs/cert.pem b/distribution/oam-controller-web/certs/cert.pem
new file mode 100644 (file)
index 0000000..1195a12
--- /dev/null
@@ -0,0 +1,102 @@
+Bag Attributes
+    friendlyName: sdnc@sdnc.onap.org
+    localKeyID: 54 69 6D 65 20 31 36 31 31 36 38 33 32 39 38 35 32 32 
+Key Attributes: <No Attributes>
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIk4s7xBaGXdgCAggA
+MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECI7qjnyFxa3mBIIEyHgvXzCmhOT/
+atHsneicZqaGXxz57z1mPosvGwf2w6WerxOyW+cFejNepgMH+c5MQAfTuTD0H5g3
+SoyC9TKfHBld439sKO3hnDBROsypugO2uP4ownGiKQxOdwHNCOS8nC1EbUYC6nHR
+B5QtRpDHZzB2t9dd6+RU1PuPUFRxjIPZsCM1DdKKhMHQHr8WDSbi170XfzC6O2Ko
+23tgDq9cQYTqmgFedjyWpEmxfcibaujGOZ4VQej+tn60A03cXHG05tN/XvDCbQty
+9bw1kiS8e+qmdUhkEIhR2aY0Z9sCUOLwJPDg/1vE0ZwK/bRGRD432PD+dmSLFV+v
+m2m/ec8IQer8hCleI6GBaFI28QZyS2jznbzS7b/hU+nyxkZXejAymU1OBcNV4H8M
+qf5ITWs+Ma5fc/8X90MlJacmBo3JuusTvDImLFP+5Nn5Yo3cnDeiAyMo0vFuywrv
+bATYAncPlzksb6py3D5iXmLxREgLI14/TdZLhcYXBHw76oPz+/CH0A2P/HICPIjr
+zF8U6zNI4bIguBTfVmm6YLjzOkVkKx4e/0fJiQO1yhzIsghhByIMg1uPcm0olNQz
+r+YRPKTqFCPRxyGgPMleN56qeLhN8Q1WyJzIJoVVpDFc+4Stbv71C/po6/6A3v4r
+hGUPCSsj8wJN+ozdamDWpeyRVCwXmmKwJU96pbnhdH/l6CPjmniAuKLzOMLJH1AD
+FJEm1Frpz40BDC2U/165+nlfcHZfePWVPpNuqWzUfywqu8ORS/pYhapFoLLafQIn
+22KhnPnbNXclIzuI0wiKjoNAfzJM0S9hysdojK/bptaZXUFeBEe41A8exuOjOxRh
+pJqqgq2cRx6cmnAy0dr54+GoZr3haQCqTk814cxumOHqQdWllblA1D9b5Wd+8T5+
+tYdzYatsvjeY/VDH5czAbUhgBHGO3Vkxm49QemcopNDeCZ7RXmSwl2X6HLfCwnfH
+9zsdNrIMfSTdRk9H4iHTyFRyoPViX6wYxlD7B9hJWggEyDVg9RvJImOSKyWk+NKd
+WmfxaywgUJkxsJeEBCso8V690lm//oWrc17qWEd29h/9J0MPNa2zXJyG1Yq1RohZ
+JW3IcnE8gCoyHVjxBCVjKPA6dXtfDNfmCDyEG+GgPglQUj9TBIRGmn9e067M6dB9
+vhnK12SBQNTyoH5vWSbP2u5wk6jV5QKYyqMbNHAD1uvsBbWy4FpoI+epp2Y3XcAr
+kgBzopKSaCbj1thxxUHsMYBspVDR+D0SR4fsHhj+Y3jmr37s3q1NOSkWUMcMa7Hi
+zaozRSo8hYUwP5RHpPcNCTcK0dhFPAWXyGPtP7IribGQDhUAdde/s4yPuSLa28zy
+uTKWU5vSlaE+9WRSKvbA8HdKTPv45dV/qUCHITvPOdsqkWJ3qhNQMrrD9Mx17oj/
+zGZTcRGQG62dfYUR9v2rGE6Gj7MzaE1SrQgYqtCzWfJ9e3fBqOlko5jtZ5Kz86DU
+ZFISrkb1sATngzWFtvyNgHFx4fUsYDJbc8XlB47H5Byyj/6SypS6dMpwqpNezn8s
+xQi3yUfpg7GQzTFKdwmqK/KVeh0KZF/0FM+ZCUPh6IaRDcp8+Hm7H72ZD4vPxs4s
+8bvLx9bxfiI+/6Om51IQrQ==
+-----END ENCRYPTED PRIVATE KEY-----
+Bag Attributes
+    friendlyName: sdnc@sdnc.onap.org
+    localKeyID: 54 69 6D 65 20 31 36 31 31 36 38 33 32 39 38 35 32 32 
+subject=CN = sdnc, OU = sdnc@sdnc.onap.org:DEV, OU = OSAAF, O = ONAP, C = US
+
+issuer=C = US, O = ONAP, OU = OSAAF, CN = intermediateCA_9
+
+-----BEGIN CERTIFICATE-----
+MIIE6zCCA9OgAwIBAgIJALyx+8HFJuYTMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV
+BAYTAlVTMQ0wCwYDVQQKDARPTkFQMQ4wDAYDVQQLDAVPU0FBRjEZMBcGA1UEAwwQ
+aW50ZXJtZWRpYXRlQ0FfOTAeFw0yMTAxMjYxNzQ4MThaFw0yMjAxMjYxNzQ4MTha
+MFwxDTALBgNVBAMMBHNkbmMxHzAdBgNVBAsMFnNkbmNAc2RuYy5vbmFwLm9yZzpE
+RVYxDjAMBgNVBAsMBU9TQUFGMQ0wCwYDVQQKDARPTkFQMQswCQYDVQQGEwJVUzCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALQtwrW3Eiru18BADUiBIbEU
+sruiLu63h6jDprLqrxGt57d5MSpxaRoOPoWDPE/Z6LvMwTGfiQIPsFnZ2H3YtDsI
+/p1fOFAHxCUl5Cs4HnYjJUkDs2U7dXUYZR8enNPZRfFZNUOajxERUgyE/0g+yHS1
+AlysMInFDblmNEYgQoNiN996FpBamHivCDXw612bBkkZQOTeKJaCZ0DPGIYGAJtf
+Q1kIL7Y1D3c3C0VD39homtxqIb21rje63YVISprbfKX0RxijkWw0wXjaRDwxPGwH
+TrDHgsrPH/zv9Hak6cJkTw5e7VBHHlL1sHYgPSDLd/8PFGkmD4a/N/IKLy/14KMC
+AwEAAaOCAcMwggG/MAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgXgMCAGA1UdJQEB
+/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBUBgNVHSMETTBLgBSB95lbELnIjN7z
+Ul7qTmmgQz6s3aEwpC4wLDEOMAwGA1UECwwFT1NBQUYxDTALBgNVBAoMBE9OQVAx
+CzAJBgNVBAYTAlVTggEHMB0GA1UdDgQWBBRUhHQPlauGoN9fiGiB7WYr+oIHJDCC
+AQkGA1UdEQSCAQAwgf2BH21hcmsuZC5tYW5hZ2VyQHBlb3BsZS5vc2FhZi5jb22C
+BHNkbmOCG2MxLnZtMS5zZG5jLnNpbXBsZWRlbW8ub25hcIIbYzIudm0xLnNkbmMu
+c2ltcGxlZGVtby5vbmFwghtjMy52bTEuc2RuYy5zaW1wbGVkZW1vLm9uYXCCG2M0
+LnZtMS5zZG5jLnNpbXBsZWRlbW8ub25hcIIJb25hcC1zZG5jgg5vbmFwLXNkbmMu
+b25hcIIcc2RuYy5hcGkuc2ltcGxlZGVtby5vbmFwLm9yZ4IJc2RuYy5vbmFwghx2
+bTEuc2RuYy5zaW1wbGVkZW1vLm9uYXAub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQAg
+7fybHysjWyKejSfPnodYuLfQoCIaXe5C4JbwLGKweAost5E6ud2rscN/c5UYNPs/
+IskfnMxULLzJpEXdUHwLQaLJj0fQQBRHq23s8P7Emu44ZeEzxAQfI+4pKRzTYxag
+4dIitf91nhUq5SQI/pcki+/ElkwfeKHYQLBDU8ygG/gZKh1UHxIjfva7v/ENqL2h
+H8UDXsLhOx/guaJzH2CRQdKMminsdtnNgSRRPzWRe4EMc2ah6G6E4B/Za/n7Rhq5
+r6jpvM/XIxPCY4ci5jJIbvdahS4I54kMaLRTSl4gT8+n8ie/GzhZlXX+1MR8HCZc
+8SWDYxmc8MkJ20iekiSc
+-----END CERTIFICATE-----
+Bag Attributes
+    friendlyName: CN=intermediateCA_9,OU=OSAAF,O=ONAP,C=US
+subject=C = US, O = ONAP, OU = OSAAF, CN = intermediateCA_9
+
+issuer=OU = OSAAF, O = ONAP, C = US
+
+-----BEGIN CERTIFICATE-----
+MIIEdTCCAl2gAwIBAgIBBzANBgkqhkiG9w0BAQsFADAsMQ4wDAYDVQQLDAVPU0FB
+RjENMAsGA1UECgwET05BUDELMAkGA1UEBhMCVVMwHhcNMTgwODE3MTg1MTM3WhcN
+MjMwODE3MTg1MTM3WjBHMQswCQYDVQQGEwJVUzENMAsGA1UECgwET05BUDEOMAwG
+A1UECwwFT1NBQUYxGTAXBgNVBAMMEGludGVybWVkaWF0ZUNBXzkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv0HHUkba3uNtNI3jPKimUcd6RNwmhSCJL
+neMWpnjqp5/A+HCKyNsEaT4y177hNLmCm/aMm1u2JIfikc+8wEqLCSBBPz+P0h+d
+o+sZ7U+4oeQizdYYpEdzHJ2SieHHa8vtu80rU3nO2NEIkuYC20HcKSEtl8fFKsk3
+nqlhY+tGfYJPTXcDOQAO40BTcgat3C3uIJHkWJJ4RivunE4LEuRv9QyKgAw7rkJV
+v+f7guqpZlXy6dzAkuU7XULWcgo55MkZlssoiErMvEZJad5aWKvRY3g7qUjaQ6wO
+15wOAUoRBW96eeZZbytgn8kybcBy++Ue49gPtgm1MF/KlAsp0MD5AgMBAAGjgYYw
+gYMwHQYDVR0OBBYEFIH3mVsQuciM3vNSXupOaaBDPqzdMB8GA1UdIwQYMBaAFFNV
+M/JL69BRscF4msEoMXvv6u1JMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B
+AQsFAAOCAgEADxNymiCNr2e37iLReoaxKmZvwox0cTiNAaj7iafRzmwIoY3VXO8Q
+ix5IYcp4FaQ7fV1jyp/AmaSnyHf6Osl0sx8PxsQkO7ALttxKUrjfbvNSVUA2C/vl
+u5m7UVJLIUtFDZBWanzUSmkTsYLHpiANFQKd2c/cU1qXcyzgJVFEFVyyHNkF7Is+
++pjG9M1hwQHOoTnEuU013P7X1mHek+RXEfhJWwe7UsZnBKZaZKbQZu7hEtqKWYp/
+QsHgnjoLYXsh0WD5rz/mBxdTdDLGpFqWDzDqb8rsYnqBzoowvsasV8X8OSkov0Ht
+8Yka0ckFH9yf8j1Cwmbl6ttuonOhky3N/gwLEozuhy7TPcZGVyzevF70kXy7g1CX
+kpFGJyEHXoprlNi8FR4I+NFzbDe6a2cFow1JN19AJ9Z5Rk5m7M0mQPaQ4RcikjB3
+aoLsASCJTm1OpOFHfxEKiBW4Lsp3Uc5/Rb9ZNbfLrwqWZRM7buW1e3ekLqntgbky
+uKKISHqVJuw/vXHl1jNibEo9+JuQ88VNuAcm7WpGUogeCa2iAlPTckPZei+MwZ8w
+tpvxTyYlZEC8DWzY1VC29+W2N5cvh01e2E3Ql08W1zL63dqrgdEZ3VWjzooYi4ep
+BmMXTvouW+Flyvcw/0oTcfN0biDIt0mCkZ5CQVjfGL9DTOYteR5hw+k=
+-----END CERTIFICATE-----
diff --git a/distribution/oam-controller-web/certs/key.pem b/distribution/oam-controller-web/certs/key.pem
new file mode 100644 (file)
index 0000000..04bc849
--- /dev/null
@@ -0,0 +1,29 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0LcK1txIq7tfA
+QA1IgSGxFLK7oi7ut4eow6ay6q8Rree3eTEqcWkaDj6FgzxP2ei7zMExn4kCD7BZ
+2dh92LQ7CP6dXzhQB8QlJeQrOB52IyVJA7NlO3V1GGUfHpzT2UXxWTVDmo8REVIM
+hP9IPsh0tQJcrDCJxQ25ZjRGIEKDYjffehaQWph4rwg18OtdmwZJGUDk3iiWgmdA
+zxiGBgCbX0NZCC+2NQ93NwtFQ9/YaJrcaiG9ta43ut2FSEqa23yl9EcYo5FsNMF4
+2kQ8MTxsB06wx4LKzx/87/R2pOnCZE8OXu1QRx5S9bB2ID0gy3f/DxRpJg+Gvzfy
+Ci8v9eCjAgMBAAECggEAbB+J2MIjhOAPWK8XSYs0TK+/EhohT9+S6RN/1Z4/sLxL
+cS6o8m9cQuaJXlWCu+hoYUpeJQk3jqUbjs/LurlwbnzXTlj10hDXA/PZGJZ0sTAm
+D8rIvNcRhVM+W45jTj30WwDNleQKNpPOSPUGvLPwVxjIchRijEpUEg3jELILOAuW
+ebloKLqc5SDAPKIpepZO7bz4L/dVlQSEBp3OTzyfeecbBNS2Vfw0K+I5BqGJAssZ
+Dq+ixSHRj6mdvm7tf5e14j65W8VKvUoHbktp9z2OBCItySV4g1dqrfM7T9SqsosH
+cbwR5dIieiFnhdg94rfpzH2QTCBt5MGUpCcv+CbQAQKBgQDkenCAImG1jAjzQNxb
+7LXLJeIqJC2E3290hEYge2Bi+1/WmV222AAwNUEPQfKa7qUJRLpX8a4p+9kTaZos
+93szyYEyp4vf93GDHvQPmKMJDCbbxa94txd5dnrtYTN+MCPjpwr+75++JRUUwcNr
+k3mkzM87zhSBkyYcGiCsza4gQQKBgQDJ4enp8Zly3GqufbWJNpKut6e9hC6f4qWi
+4qRUBmjnogm0HiGmn83n9B6SI6OnaRy/dXgPBogZDeETyzGu78nArDK+cy8wSy0H
+aPuApqGJzsuAl6YWudYt4ooBcJL99XgTGxFAb2q04JKxh18V6DRfj7pY2uhZongI
+OdcMSE2H4wKBgQCUzNEcAkhUbmEd264oCB/VsFR9UZZ7pPD3l3X8jZ2WmVQvdS69
+eCuXOfenMjIIiUfeo24g/HuLSER2Ch6pDnykm6WTEd9c+9Bnru8QgT4dFFbyZusC
+2WtmZa1lkBpzInMdPptAsVr+ATSbkh3tn9xnYiPNNUfRo738K2AAauvugQKBgQCd
+dzbqoOXdr4sOm0LzybtTyDBwJB/x2ej0Se9/EpjUw5DqCu6YduE2YTVPK7lEpTol
+JE0G+0NAt5CtzbntB1/Ihwf1gQZ3lsuCkiJJ0K8DPGeC38ZOx5kFpUObp+EfcU29
+KUmlhsImX1xMWJiUD9B6ETN6hxTghVc2o1bXX7YJnQKBgQCGiRnjCEmKd8hefkS8
+ub9F4kdOzXmG4XhK+oZWVGPXIGfnoxm6IbWcjSArA/m8TLfJSHPKujnLOnOkffpi
+7+PWzTHn5BFDGUb8z3mxwJV8e9szoDkljoiUwYU/S8eatAm6lyJv1gp2wmDI9DfT
+86BefCEvGk3EzAo3L6hhHdICzA==
+-----END PRIVATE KEY-----
+
diff --git a/distribution/oam-controller-web/pom.xml b/distribution/oam-controller-web/pom.xml
new file mode 100644 (file)
index 0000000..7e6365b
--- /dev/null
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.o-ran-sc.sdnc.oam</groupId>
+    <artifactId>installation-sdnc-web</artifactId>
+    <version>2.6.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>sdnc-oam :: installation :: ${project.artifactId}</name>
+    <description>Creates SDN Controller WebUI Docker container</description>
+
+    <properties>
+        <base.image.repo>docker.io/bitnami/nginx:1.21-debian-10</base.image.repo>
+        <image.name>o-ran-sc/sdnc-web-image</image.name>
+        <sdnc.project.version>${project.version}</sdnc.project.version>
+        <ccsdk.features.version>1.7.0-SNAPSHOT</ccsdk.features.version>
+        <sdnc.build.timestamp>${maven.build.timestamp}</sdnc.build.timestamp>
+        <docker.buildArg.https_proxy>${https_proxy}</docker.buildArg.https_proxy>
+        <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+        <docker.push.phase>deploy</docker.push.phase>
+        <docker.verbose>true</docker.verbose>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.o-ran-sc.oam-controller.features.sdnr.odlux</groupId>
+            <artifactId>sdnr-odlux-installer</artifactId>
+            <version>${ccsdk.features.version}</version>
+            <type>zip</type>
+            <classifier>repo</classifier>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.gmaven</groupId>
+                <artifactId>groovy-maven-plugin</artifactId>
+                <version>2.1.1</version>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>${basedir}/../TagVersion.groovy</source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>2.6</version>
+                <executions>
+                    <execution>
+                        <id>copy-dockerfile</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                                               <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/docker</directory>
+                                    <includes>
+                                        <include>Dockerfile</include>
+                                    </includes>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-siteconf</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                                               <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/conf</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/resources</directory>
+                                    <includes>
+                                        <include>*.conf</include>
+                                        <include>*.rules</include>
+                                    </includes>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-scripts</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                                               <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/bin</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/scripts</directory>
+                                    <includes>
+                                        <include>*.sh</include>
+                                        <include>*.py</include>
+                                    </includes>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-favicon</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/html</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/resources</directory>
+                                    <includes>
+                                        <include>favicon.ico</include>
+                                        <include>odlux.application.list</include>
+                                    </includes>
+                                    <filtering>false</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack features</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>unpack-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/html</outputDirectory>
+                            <excludeTransitive>true</excludeTransitive>
+                            <overWriteReleases>false</overWriteReleases>
+                            <overWriteSnapshots>true</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <version>0.30.0</version>
+                <inherited>false</inherited>
+                <configuration>
+                    <images>
+                        <image>
+                            <name>${image.name}</name>
+                            <build>
+                                <cleanup>try</cleanup>
+                                <dockerFileDir>${basedir}/target/docker-stage</dockerFileDir>
+                                       <!--  <dockerFile>${basedir}/target/docker-stage/Dockerfile</dockerFile> -->
+                                <tags>
+                                    <tag>${project.docker.latestminortag.version}</tag>
+                                    <tag>${project.docker.latestfulltag.version}</tag>
+                                    <tag>${project.docker.latesttagtimestamp.version}</tag>
+                                </tags>
+                            </build>
+                        </image>
+                    </images>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>generate-images</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>build</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>push-images</id>
+                        <phase>${docker.push.phase}</phase>
+                        <goals>
+                            <goal>build</goal>
+                            <goal>push</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/distribution/oam-controller-web/src/main/docker/Dockerfile b/distribution/oam-controller-web/src/main/docker/Dockerfile
new file mode 100644 (file)
index 0000000..b2b45a3
--- /dev/null
@@ -0,0 +1,65 @@
+###
+#============LICENSE_START=======================================================
+# ONAP : ccsdk distribution web
+#  ================================================================================
+# Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+# All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+
+# Base bitnami nginx image
+FROM ${base.image.repo}
+LABEL maintainer="CCSDK Team (onap-ccsdk@lists.onap.org)"
+USER root
+RUN apt-get update && apt-get install python3-minimal python3-urllib3 unzip openssl -y
+USER 1001
+# copy ODLUX files to nginx
+COPY html /opt/bitnami/nginx/html  
+
+# copy site conf files 
+COPY conf/* /opt/bitnami/nginx/conf/server_blocks/
+
+# setup environment variables
+ENV WEBPROTOCOL="HTTP" \
+    WEBPORT="8080" \
+    SDNRPROTOCOL="HTTP" \
+    SDNRHOST="172.18.0.3" \
+    SDNRPORT="8181" \
+    ONETONSETUP="false" \
+    TRPCEURL="" \
+    TOPOURL="" \
+    TILEURL="" \
+    SITEDOCURL="" \
+    DNS_RESOLVER="1.1.1.1 ipv6=off" \
+    DNS_INTERNAL_RESOLVER="127.0.0.11" \
+    SSL_CERT_DIR="/app/cert" \
+    SSL_CERTIFICATE="cert.pem" \
+    SSL_CERTIFICATE_KEY="cert.key"
+
+# Check if /app can be used. If so, create "custom" directory and copy the files there.
+COPY bin/* /opt/bitnami/nginx/sbin/ 
+
+USER root
+RUN chmod +x /opt/bitnami/nginx/sbin/run.sh /opt/bitnami/nginx/sbin/opm.py
+# By default, docker copies files with the permissions of the build user. To avoid cases where build user 
+# has 644 which can result in failure of certain commands
+RUN chmod -R g+w /opt/bitnami/nginx/html/odlux && mkdir /app/init.d
+RUN chmod 666 /opt/bitnami/nginx/conf/server_blocks/*.rules
+#RUN chown 1001:1001 /app/odlux.application.list && chmod 777 /app/odlux.application.list
+RUN chown -R 1001:1001 /app
+RUN ln -s /opt/bitnami/nginx/sbin/opm.py /usr/local/bin/opm
+USER 1001
+CMD [ "/opt/bitnami/nginx/sbin/run.sh" ]
+
diff --git a/distribution/oam-controller-web/src/main/resources/favicon.ico b/distribution/oam-controller-web/src/main/resources/favicon.ico
new file mode 100644 (file)
index 0000000..650067e
Binary files /dev/null and b/distribution/oam-controller-web/src/main/resources/favicon.ico differ
diff --git a/distribution/oam-controller-web/src/main/resources/http_custom.conf b/distribution/oam-controller-web/src/main/resources/http_custom.conf
new file mode 100644 (file)
index 0000000..fd637dd
--- /dev/null
@@ -0,0 +1,4 @@
+map $http_authorization $auth_header {
+    ~^Basic     $http_authorization;       
+    default     "Bearer $cookie_token";
+}
diff --git a/distribution/oam-controller-web/src/main/resources/http_site.conf b/distribution/oam-controller-web/src/main/resources/http_site.conf
new file mode 100644 (file)
index 0000000..1fe4303
--- /dev/null
@@ -0,0 +1,66 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : ccsdk distribution web
+# ================================================================================
+# Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+# All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+
+##
+# You should look at the following URL's in order to grasp a solid understanding
+# of Nginx configuration files in order to fully unleash the power of Nginx.
+# https://www.nginx.com/resources/wiki/start/
+# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
+# https://wiki.debian.org/Nginx/DirectoryStructure
+#
+# In most cases, administrators will remove this file from sites-enabled/ and
+# leave it as reference inside of sites-available where it will continue to be
+# updated by the nginx packaging team.
+#
+# This file will automatically load configuration files provided by other
+# applications, such as Drupal or Wordpress. These applications will be made
+# available underneath a path with that package name, such as /drupal8.
+#
+# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
+##
+
+# Default server configuration
+#
+server {
+    listen WEBPORT default_server ;
+    listen [::]:WEBPORT default_server;
+
+#   root /var/www;
+
+    index index.html index.htm index.nginx-debian.html;
+
+    server_name _;
+
+    include server_blocks/location.rules;
+
+    gzip on;
+    gzip_min_length 1000;
+    gzip_comp_level 5;
+    gzip_proxied any;
+    gzip_vary on;
+    gzip_types text/plain
+                application/json
+                application/xml
+                application/yang-data+json
+                application/yang-data+xml
+                text/javascript
+                application/javascript;
+}
diff --git a/distribution/oam-controller-web/src/main/resources/https_site.conf b/distribution/oam-controller-web/src/main/resources/https_site.conf
new file mode 100644 (file)
index 0000000..734a48b
--- /dev/null
@@ -0,0 +1,85 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : ccsdk distribution web
+# ================================================================================
+# Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+# All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+
+##
+# You should look at the following URL's in order to grasp a solid understanding
+# of Nginx configuration files in order to fully unleash the power of Nginx.
+# https://www.nginx.com/resources/wiki/start/
+# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
+# https://wiki.debian.org/Nginx/DirectoryStructure
+#
+# In most cases, administrators will remove this file from sites-enabled/ and
+# leave it as reference inside of sites-available where it will continue to be
+# updated by the nginx packaging team.
+#
+# This file will automatically load configuration files provided by other
+# applications, such as Drupal or Wordpress. These applications will be made
+# available underneath a path with that package name, such as /drupal8.
+#
+# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
+##
+
+# Default server configuration
+#
+server {
+    listen WEBPORT ssl default_server ;
+    listen [::]:WEBPORT ssl default_server;
+
+    # SSL configuration
+    #
+    # listen 443 ssl default_server;
+    # listen [::]:443 ssl default_server;
+    #
+    # Note: You should disable gzip for SSL traffic.
+    # See: https://bugs.debian.org/773332
+    #
+    # Read up on ssl_ciphers to ensure a secure configuration.
+    # See: https://bugs.debian.org/765782
+    #
+    # Self signed certs generated by the ssl-cert package
+    # Don't use them in a production server!
+    #
+    # include snippets/snakeoil.conf;
+
+    ssl_certificate SSL_CERT_DIR/SSL_CERTIFICATE;
+    ssl_certificate_key SSL_CERT_DIR/SSL_CERTIFICATE_KEY;
+
+#   root /var/www;
+
+    index index.html index.htm index.nginx-debian.html;
+
+    server_name _;
+
+    include server_blocks/location.rules;
+  
+    gzip on;
+    gzip_min_length 1000;
+    gzip_comp_level 5;
+    gzip_proxied any;
+    gzip_vary on;
+    gzip_types text/plain
+                application/json
+                application/xml
+                application/yang-data+json
+                application/yang-data+xml
+                text/javascript
+                application/javascript;
+}
diff --git a/distribution/oam-controller-web/src/main/resources/location.rules b/distribution/oam-controller-web/src/main/resources/location.rules
new file mode 100644 (file)
index 0000000..0342e31
--- /dev/null
@@ -0,0 +1,64 @@
+location ~ ^/$  {
+    return 301 " /odlux/index.html";
+}
+location ~ ^/help/$  {
+    try_files /help/$args.json $uri;
+}
+location ~ ^/transportpce  {
+    resolver DNS_INTERNAL_RESOLVER;
+    if ($request_uri ~* "/transportpce/(.*)") { 
+        proxy_pass TRPCEURL/$1;
+    }
+}
+location ~ ^/topology/  {
+    resolver DNS_INTERNAL_RESOLVER;
+    proxy_pass TOPOURL;
+}
+location ~ ^/sitedoc/  {
+  resolver DNS_INTERNAL_RESOLVER;
+  if ($request_uri ~* "/sitedoc/(.*)") {
+    proxy_pass SITEDOCURL/topology/stadok/$1;
+  }
+}
+location ~ ^/tiles/  {
+    resolver DNS_RESOLVER;
+    if ($request_uri ~* "/tiles/(.*)") { 
+        proxy_pass TILEURL/$1;
+    }
+}
+location ~ ^/terrain/  {
+  resolver DNS_INTERNAL_RESOLVER;
+  if ($request_uri ~* "/terrain/(.*)") {
+    proxy_pass TERRAINURL/$1;
+  }
+}
+location ~ ^/electromagnetic-field/  {
+  resolver DNS_RESOLVER;
+  proxy_set_header Authorization "Basic ELECTROMAGNETICFIELDBAUTHTOKEN";
+  proxy_pass_header Authorization;
+  if ($request_uri ~* "/electromagnetic-field/(.*)") {
+    proxy_pass ELECTROMAGNETICFIELDURL/$1;
+  }
+}
+location /  {
+    try_files $uri $uri/ @backend;
+}
+location /websocket {
+    proxy_pass http://SDNRHOST:SDNRWEBSOCKETPORT/websocket;
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+}
+location /apidoc/ {
+    proxy_pass SDNRPROTOCOL://SDNRHOST:SDNRPORT;
+
+    # Inject Authorization header
+    proxy_set_header Authorization $auth_header;
+    #
+    # Optional CORS settings
+    #add_header Access-Control-Allow-Origin *;
+    add_header Access-Control-Allow-Headers Authorization,Content-Type;
+}
+location @backend {
+    proxy_pass SDNRPROTOCOL://SDNRHOST:SDNRPORT;
+}
\ No newline at end of file
diff --git a/distribution/oam-controller-web/src/main/resources/odlux.application.list b/distribution/oam-controller-web/src/main/resources/odlux.application.list
new file mode 100644 (file)
index 0000000..c56559c
--- /dev/null
@@ -0,0 +1,8 @@
+1 connectApp
+10 faultApp
+20 maintenanceApp
+30 configurationApp
+55 performanceHistoryApp
+70 inventoryApp
+75 eventLogApp
+200 helpApp
diff --git a/distribution/oam-controller-web/src/main/scripts/configure.py b/distribution/oam-controller-web/src/main/scripts/configure.py
new file mode 100644 (file)
index 0000000..255cbcd
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+###
+# ============LICENSE_START=======================================================
+# ONAP : ccsdk distribution web
+# ================================================================================
+# Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+# All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+
+# load core methods to call
+from core import *
+
+# Comment listening on 8080 in nginx.conf as we don't want nginx to listen on any port other than SDNR
+sedInFile('listen','\#listen', '/opt/bitnami/nginx/conf/nginx.conf')
+initial_load()
+update_index_html()
+
+check_for_rule_template()
+
+update_nginx_site_conf()
diff --git a/distribution/oam-controller-web/src/main/scripts/core.py b/distribution/oam-controller-web/src/main/scripts/core.py
new file mode 100644 (file)
index 0000000..461f8cd
--- /dev/null
@@ -0,0 +1,358 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : ccsdk distribution web
+# ================================================================================
+# Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+# All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+import subprocess
+import os
+import json
+import zipfile
+import re
+import uuid
+import urllib3
+import shutil
+import re
+import ssl
+urllib3.disable_warnings()
+
+APPLICATION_LISTFILE="/app/odlux.application.list"
+INIT_FOLDER="/app/init.d"
+ODLUX_BASE_FOLDER='/app/odlux'
+INDEX_HTML=ODLUX_BASE_FOLDER+'/index.html'
+INDEX_HTML_TEMPLATE=INDEX_HTML+'.template'
+DEFAULT_APPLICATIONS=["connectApp" "faultApp" "maintenanceApp" "configurationApp" "performanceHistoryApp" "inventoryApp" "eventLogApp" "mediatorApp" "helpApp"]
+http = urllib3.PoolManager(cert_reqs=ssl.CERT_NONE)
+    
+def exec(command):
+    output = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout.read()
+    return output
+def execToStdOut(commandArray):
+    process = subprocess.Popen(commandArray, shell=False)
+    process.communicate()
+
+def download(url, dst):
+    print("downloading from {}...".format(url),end="")
+    with open(dst, 'wb') as out_file:
+        resp= http.request('GET',url, preload_content=False)
+        shutil.copyfileobj(resp, out_file)
+        resp.release_conn() 
+    print("done")
+
+def getEnv(key, defaultValue=None):
+    x=os.getenv(key)
+    return x if x is not None and len(x)>0 else defaultValue
+
+def sedInFile(old, nu, fn):
+    execToStdOut(['sed', '-i', 's|{}|{}|g'.format(old,nu),fn])
+
+def add_application(name, index, file=None):
+    apps = load_applications()
+    if index==0:
+        print("no index given. put it to last position")
+        index=apps[len(apps)-1]['index']+10
+    apps.append(dict(index=index,name=name))
+    if file is not None and os.path.exists(file):
+        extract(file)
+    else:
+        print('unable to find file {}'.format(file))
+    write_applications(apps)
+    print("{} installed on index {}".format(name, index)) 
+
+def initial_load():
+    files = os.listdir(INIT_FOLDER)
+    regex = r"([0-9]+)([a-zA-Z]+)\.(jar|zip)"
+    regexUrl = r"([0-9]+)([a-zA-Z]+)\.(url)"
+    for file in files:
+        matches = re.finditer(regex,file)
+        match = next(matches, None)
+        matchesUrl = re.finditer(regexUrl,file)
+        matchUrl = next(matchesUrl, None)
+        if match is not None:
+            print("installing {}".format(file))
+            index = int(match.group(1))
+            name = match.group(2)
+            add_application(name,index,INIT_FOLDER+'/'+file)
+        elif matchUrl is not None:
+            print("installing {}".format(file))
+            index = int(match.group(1))
+            name = match.group(2)
+            add_application(name,index,INIT_FOLDER+'/'+file)
+        else:
+            print("no index naming format found. try to autodetect")
+            infos = autoDetectInfosFromJar(file)
+            if infos is None:
+                print("unable to detect index and application name for {}".format(file))
+            else:
+               add_application(infos['name'],infos['index'],INIT_FOLDER+'/'+file) 
+
+
+
+def containsBlueprintExpression(file) -> bool:
+    print("check if file {} is blueprint".format(file))
+    with open(file, 'r') as fp:
+        lines = fp.readlines()
+        for line in lines:
+            if "<blueprint" in line:
+                return True
+        fp.close()
+    return False
+
+def findBlueprintXml(dir):
+    result = [os.path.join(dp, f) for dp, dn, filenames in os.walk(dir) for f in filenames if os.path.splitext(f)[1] == '.xml']
+    for file in result:
+        if containsBlueprintExpression(file):
+            return file
+    return None
+
+def autoDetectInfosFromJar(file):
+    print("autodetect infos(appName and index) from jar {}".format(file))
+    tmpDir=getRandomTempDir()
+    regexBundleName = r"<property[\ ]+name=\"bundleName\"[\ ]+value=\"([^\"]+)\""
+    regexIndex = r"<property[\ ]+name=\"index\"[\ ]+value=\"([^\"]+)\""
+    name=None
+    index=0
+    with zipfile.ZipFile(file, 'r') as zip_ref:
+        zip_ref.extractall(tmpDir)
+        blueprint = findBlueprintXml(tmpDir)
+        if blueprint is None:
+            return None
+        with open(blueprint) as fp:
+            lines = fp.readlines()
+            for line in lines:
+                if name is None:
+                    matches = re.finditer(regexBundleName, line)
+                    match = next(matches,None)
+                    if match is not None:
+                        name = match.group(1)
+                if index == 0:
+                    matches = re.finditer(regexIndex, line)
+                    match = next(matches,None)
+                    if match is not None:
+                        index = int(match.group(1))
+       
+            fp.close()
+    print("found infos from jar: name={} index={}".format(name,index))
+    return dict(index=index,name=name)
+        
+def getRandomTempDir(create=False):
+    while(True):
+        dir='/tmp/{}'.format(uuid.uuid4())
+        if not os.path.exists(dir):
+#            print("found random not-existing dir {}".format(dir))
+            if create:
+                os.makedirs(dir)
+            return dir
+#        print("dir {} already exists. try new".format(dir))
+    return None
+
+def getRandomTempFile():
+    dir = getRandomTempDir(True)
+    if dir is None:
+        return None
+
+    while True:
+        file='{}/{}.dat'.format(dir,uuid.uuid4())
+        if not os.path.exists(file):
+#            print("found random not-existing file {}".format(file))
+            return file
+#        print("file {} already exists. try new".format(file))
+    return None
+
+def extract(fn):
+
+    tmpDir=getRandomTempDir()  
+    with zipfile.ZipFile(fn, 'r') as zip_ref:
+        zip_ref.extractall(tmpDir)
+        exec(" ".join(['cp','-r',tmpDir+'/odlux/*',ODLUX_BASE_FOLDER+'/']))
+        zip_ref.close()
+
+
+def load_applications():
+    apps=[]
+    if os.path.exists(APPLICATION_LISTFILE):
+        with open(APPLICATION_LISTFILE,'r') as fp:
+            lines= fp.readlines()
+            for line in lines:
+                if len(line.rstrip())<=0:
+                    continue
+                try:
+                    hlp=line.split(' ')
+                    apps.append(dict(index=int(hlp[0]),name=hlp[1].rstrip()))
+                except:
+                    print('problem reading line {}'.format(line))
+            fp.close()
+    else:
+        index=10
+        for app in DEFAULT_APPLICATIONS:
+            apps.append(dict(index=index,name=app))
+            index+=10
+#    print('applications loaded={}'.format(apps))
+    return sorted(apps, key=lambda d: d['index']) 
+  
+def write_applications(apps):
+#    print('saving applications={}'.format(apps))
+    apps = sorted(apps, key=lambda d: d['index'])
+    os.remove(APPLICATION_LISTFILE)
+    with open(APPLICATION_LISTFILE,'w') as fp:
+        for app in apps:
+            fp.write('{} {}\n'.format(app['index'], app['name']))
+        fp.close()
+
+def update_index_html(apps=None):
+#     # Backup the index.html file
+    if not os.path.exists(INDEX_HTML_TEMPLATE):
+        execToStdOut(['cp',INDEX_HTML,INDEX_HTML_TEMPLATE])
+    else:
+        execToStdOut(['cp',INDEX_HTML_TEMPLATE,INDEX_HTML])
+#     #default values
+    if apps is None:
+        apps=load_applications()
+    ODLUX_AUTH_METHOD="basic"
+    ENABLE_ODLUX_RBAC=getEnv('ENABLE_ODLUX_RBAC','false')
+    TRPCEGUIURL=getEnv('TRPCEGUIURL')
+
+    if getEnv('ENABLE_OAUTH') == "true":
+        ODLUX_AUTH_METHOD="oauth"
+    ODLUX_CONFIG=dict(authentication=ODLUX_AUTH_METHOD,enablePolicy=ENABLE_ODLUX_RBAC == 'true')
+    print("authentication is {}".format(ODLUX_AUTH_METHOD))
+    print("rbac access is enabled: {}".format(ENABLE_ODLUX_RBAC))
+   
+    if TRPCEGUIURL is not None:
+        ODLUX_CONFIG['transportpceUrl']=TRPCEGUIURL
+        print("trpce gui url is: {}".format(TRPCEGUIURL))
+
+#    sed -z 's/<script>[^<]*<\/script>/<script>\n    \/\/ run the application \n  require\(\[\"connectApp\",\"faultApp\",\"maintenanceApp\",\"configurationApp\",\"performanceHistoryApp\",\"inventoryApp\",\"eventLogApp\",\"mediatorApp\",\"networkMapApp\",\"microwaveApp\",\"helpApp\",\"run\"\], function \(connectApp,faultApp,maintenanceApp,configurationApp,performanceHistoryApp,inventoryApp,eventLogApp,mediatorApp,networkMapApp,microwaveApp,helpApp,run\) \{ \n run.configure('$ODLUX_CONFIG'); \n    connectApp.register\(\); \n  faultApp.register\(\);\n    maintenanceApp.register\(\); \n     configurationApp.register\(\);\n    performanceHistoryApp.register\(\); \n    inventoryApp.register\(\);\n    eventLogApp.register\(\);\n   mediatorApp.register\(\);\n   networkMapApp.register\(\);\n   microwaveApp.register\(\);\n     helpApp.register\(\);\n      run.runApplication();\n    \}\);\n  <\/script>/' -i /opt/bitnami/nginx/html/odlux/index.html 
+    requireArg=""
+    fnArgs=""
+    appCalls=""
+    for app in apps:
+        requireArg+='"{}",'.format(app['name'])
+        fnArgs+='{},'.format(app['name'])
+        appCalls+='{}.register();\\n'.format(app['name'])
+    #replace require expression
+    execToStdOut(['sed', '-z', 's/require(\["run"\],\ function\ (run)/require\(\[{}\"run\"\], function \({}run\)/'.format(requireArg,fnArgs), '-i', INDEX_HTML]) 
+    #replace run.runApplication expression
+    execToStdOut(['sed','-z', 's/run.runApplication();/{}run.runApplication();/'.format(appCalls), '-i',INDEX_HTML])
+    #replace run.configure expression if exists
+    execToStdOut(['sed', '-z', 's|run.configureApplication([^)]\+)|run.configureApplication({});|'.format(json.dumps(ODLUX_CONFIG)), '-i', INDEX_HTML]) 
+  
+
+def check_for_rule_template():
+    if os.path.exists('/opt/bitnami/nginx/conf/server_blocks/location.rules.tmpl'):
+        print("using template for forwarding rules")
+        execToStdOut(['cp','/opt/bitnami/nginx/conf/server_blocks/location.rules.tmpl','/opt/bitnami/nginx/conf/server_blocks/location.rules'])
+
+def update_nginx_site_conf():
+    FN=None
+    if getEnv('WEBPROTOCOL') == "HTTPS":
+        FN='/opt/bitnami/nginx/conf/server_blocks/https_site.conf'
+        execToStdOut(['rm', '/opt/bitnami/nginx/conf/server_blocks/http_site.conf'])
+        SSL_CERT_DIR=getEnv('SSL_CERT_DIR')
+        SSL_CERTIFICATE=getEnv('SSL_CERTIFICATE')
+        SSL_CERTIFICATE_KEY=getEnv('SSL_CERTIFICATE_KEY')
+        sedInFile('SSL_CERTIFICATE_KEY',SSL_CERTIFICATE_KEY,FN)
+        sedInFile('SSL_CERT_DIR',SSL_CERT_DIR,FN)
+        sedInFile('SSL_CERTIFICATE',SSL_CERTIFICATE, FN)
+        
+    elif getEnv('WEBPROTOCOL') == "HTTP":
+        FN='/opt/bitnami/nginx/conf/server_blocks/http_site.conf'
+        execToStdOut(['rm', '/opt/bitnami/nginx/conf/server_blocks/https_site.conf'])
+
+    WEBPROTOCOL=getEnv('WEBPROTOCOL')
+    WEBPORT=getEnv('WEBPORT')
+    SDNRPROTOCOL=getEnv('SDNRPROTOCOL')
+    SDNCWEBHOST=getEnv('HOSTNAME')
+    SDNRHOST=getEnv('SDNRHOST')
+    if getEnv('ONETONSETUP') == "true":
+        if SDNRHOST == "sdnc.onap":
+            # Request is from K8s
+            SDNCWEBHOSTINDEX=SDNCWEBHOST[SDNCWEBHOST.rindex("-")+1:]
+            SDNRHOST = "sdnc-" + SDNCWEBHOSTINDEX + ".onap" 
+    SDNRPORT=getEnv('SDNRPORT')
+    SDNRWEBSOCKETPORT=getEnv('SDNRWEBSOCKETPORT',SDNRPORT)
+    DNS_RESOLVER=getEnv('DNS_RESOLVER')
+    DNS_INTERNAL_RESOLVER=getEnv('DNS_INTERNAL_RESOLVER')
+    if FN is None:
+        print("unknown env WEBPROTOCOL: {}".format(WEBPROTOCOL))
+        exit(1)
+    
+    # replace needed base parameters
+    sedInFile('WEBPORT',WEBPORT,FN)
+
+    FN='/opt/bitnami/nginx/conf/server_blocks/location.rules'
+    # replace needed parameters in forwarding rules
+    sedInFile('WEBPORT',WEBPORT,FN)
+    sedInFile('SDNRPROTOCOL',SDNRPROTOCOL,FN)
+    sedInFile('SDNRHOST',SDNRHOST ,FN)
+    sedInFile('SDNRPORT',SDNRPORT,FN)
+    sedInFile('SDNRWEBSOCKETPORT',SDNRWEBSOCKETPORT, FN)
+    sedInFile('DNS_RESOLVER',DNS_RESOLVER ,FN)
+    sedInFile('DNS_INTERNAL_RESOLVER',DNS_INTERNAL_RESOLVER ,FN)
+
+    TRPCEURL=getEnv('TRPCEURL')
+    TOPOURL=getEnv('TOPOURL')
+    SITEDOCURL=getEnv('SITEDOCURL')
+    TILEURL=getEnv('TILEURL')
+    DATAPROVIDERURL=getEnv('DATAPROVIDERURL')
+    TERRAINURL=getEnv('TERRAINURL')
+    ELECTROMAGNETICFIELDURL=getEnv('ELECTROMAGNETICFIELDURL')
+    ELECTROMAGNETICFIELDBAUTHTOKEN=getEnv('ELECTROMAGNETICFIELDBAUTHTOKEN')
+    # handle optional parameters
+    if TRPCEURL is None:
+        print("transportPCE forwarding disabled")
+        sedInFile('proxy_pass TRPCEURL/$1;','return 404;',FN)
+    else:
+        sedInFile('TRPCEURL',TRPCEURL ,FN)
+
+    if TOPOURL is None:
+        print("topology api forwarding disabled")
+        sedInFile('proxy_pass TOPOURL;','return 404;',FN)
+    else:
+        sedInFile('TOPOURL',TOPOURL ,FN)
+    
+    if SITEDOCURL is None:
+        print("sitedoc api forwarding disabled")
+        sedInFile('proxy_pass SITEDOCURL/topology/stadok/$1;','return 404;', FN)
+    else:
+        sedInFile('SITEDOCURL',SITEDOCURL, FN)
+    
+    if TILEURL is None:
+        print("tile server forwarding disabled")
+        sedInFile('proxy_pass TILEURL/$1;','return 404;',FN)
+    else:
+        sedInFile('TILEURL',TILEURL ,FN)
+    
+    if DATAPROVIDERURL is None:
+        print("data provider forwarding disabled")
+        sedInFile('proxy_pass DATAPROVIDERURL/$1;','return 404;',FN)
+    else:
+        sedInFile('DATAPROVIDERURL',DATAPROVIDERURL ,FN)
+    
+    if TERRAINURL is None:
+        print("terrain server forwarding disabled")
+        sedInFile('proxy_pass TERRAINURL/$1;','return 404;',FN)
+    else:
+        sedInFile('TERRAINURL',TERRAINURL ,FN)
+        
+    if ELECTROMAGNETICFIELDURL is None:
+        print("electromagnetic-field server forwarding disabled")
+        sedInFile('proxy_pass ELECTROMAGNETICFIELDURL/$1;','return 404;',FN)
+    else:
+        sedInFile('ELECTROMAGNETICFIELDURL',ELECTROMAGNETICFIELDURL ,FN)
+        sedInFile('ELECTROMAGNETICFIELDBAUTHTOKEN',ELECTROMAGNETICFIELDBAUTHTOKEN ,FN)       
diff --git a/distribution/oam-controller-web/src/main/scripts/opm.py b/distribution/oam-controller-web/src/main/scripts/opm.py
new file mode 100755 (executable)
index 0000000..955822a
--- /dev/null
@@ -0,0 +1,126 @@
+#!/usr/bin/python3
+###
+# ============LICENSE_START=======================================================
+# ONAP : ccsdk distribution web
+# ================================================================================
+# Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+# All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+
+# opm = ODLUX package manager
+# install odlux application inside of the container
+# $1 install|uninstall
+# $2 appName
+# $3 zip file to add(extract)
+
+import sys
+from core import *
+
+
+
+
+# install application
+# $1 appName
+# $2
+# $2 zip file (optional)
+def run_install(name, index=0, file=None):
+    if name is None:
+        error("no name given")
+    add_application(name, index, file)
+    update_index_html()
+
+
+# install application from url
+# $1 url
+# $2 name (optional)
+# $3 index (optional)
+def run_install_from_url(url, name=None, index=0):
+    if url is None:
+        error("no url given")
+    print("installing from url...")
+    localFile = getRandomTempFile()
+    download(url,localFile)
+    if (name is None) or (index==0):
+        infos = autoDetectInfosFromJar(localFile)
+        if infos is not None:
+            if name is None:
+                name = infos['name']
+            if index == 0:
+                index = infos['index']
+    add_application(name,index,localFile)
+
+# uninstall application
+# $1 appName
+def run_uninstall(name):
+    if name is None:
+        error("no name given")
+    apps = load_applications()
+    apps = [app for app in apps if app['name']!=name]
+    write_applications(apps)
+    update_index_html()
+    
+def run_list(args):
+    apps = load_applications()
+    print('installed apps') 
+    for app in apps:
+        print('{} {}'.format(app['index'],app['name']))
+    
+def print_help():
+    print("ODLUX package manager")
+    print("=====================")
+    print("usage:")
+    print(" opm.py install --name myApplication --index 23 --file app.zip")
+    print(" opm.py install --url https://link-to-my-odlux-application.jar")
+    print(" opm.py list")
+    print(" opm.py uninstall --name myApplication")
+
+def error(msg):
+    print('ERROR: {}'.format(msg))
+    exit(1)
+
+args = sys.argv
+args.pop(0)
+cmd = args.pop(0)
+name=None
+index=0
+file=None
+url=None
+while(len(args)>0):
+    x=args.pop(0)
+    if x=='--name':
+        name=args.pop(0) if len(args)>0 else error("no name given")
+    elif x=='--index':
+        index=int(args.pop(0)) if len(args)>0 else error("no index given")
+    elif x=='--file':
+        file=args.pop(0) if len(args)>0 else error("no file given")
+    elif x=='--url':
+        url=args.pop(0) if len(args)>0 else error("no file given")
+    
+print("command={} name={} index={} file={} url={}".format(cmd,name,index, file, url))
+       
+if cmd=='install':
+    if url is not None:
+        run_install_from_url(url, name, index)
+    else:
+        run_install(name,index,file)
+elif cmd=='uninstall':
+    run_uninstall(name)
+elif cmd=='list':
+    run_list(args)
+else:
+    print_help
+    exit(1)
+exit(0)
diff --git a/distribution/oam-controller-web/src/main/scripts/run.sh b/distribution/oam-controller-web/src/main/scripts/run.sh
new file mode 100644 (file)
index 0000000..e8e492b
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+###
+#============LICENSE_START=======================================================
+# ONAP : ccsdk distribution web
+#================================================================================
+# Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+# All rights reserved.
+#================================================================================
+# 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.
+#============LICENSE_END=========================================================
+###
+python3 /opt/bitnami/nginx/sbin/configure.py
+
+echo "starting sdnc-web"
+echo "======================="
+echo " WEBPROTOCOL                      : $WEBPROTOCOL"
+echo " WEBPORT                          : $WEBPORT"
+echo " SDNRPROTOCOL                     : $SDNRPROTOCOL"
+echo " SDNRHOST                         : $SDNRHOST"
+echo " SDNRPORT                         : $SDNRPORT"
+echo " SDNRWEBSOCKETPORT                : $SDNRWEBSOCKETPORT"
+echo " DNS_RESOLVER                     : $DNS_RESOLVER"
+echo " DNS_INTERNAL_RESOLVER            : $DNS_INTERNAL_RESOLVER"
+echo " TRPCEURL                         : $TRPCEURL"
+echo " TRPCEGUIURL                      : $TRPCEGUIURL"
+echo " TOPOURL                          : $TOPOURL"
+echo " TILEURL                          : $TILEURL"
+echo " SITEDOCURL                       : $SITEDOCURL"
+echo " ELECTROMAGNETICFIELDURL          : $ELECTROMAGNETICFIELDURL"
+echo " ELECTROMAGNETICFIELDBAUTHTOKEN   : ${ELECTROMAGNETICFIELDBAUTHTOKEN:0:5}...${ELECTROMAGNETICFIELDBAUTHTOKEN: -5}"
+echo "======================="
+if [ "$WEBPROTOCOL" == "HTTPS" ]; then
+  echo " SSL_CERT_DIR : $SSL_CERT_DIR"
+  echo -n " SSL_CERTIFICATE: $SSL_CERTIFICATE"
+  if [ -f "$SSL_CERT_DIR/$SSL_CERTIFICATE" ]; then
+    echo " (exists)"
+  else
+    echo " (missing)"
+  fi
+  echo -n " SSL_CERTIFICATE_KEY: $SSL_CERTIFICATE_KEY"
+  if [ -f "$SSL_CERT_DIR/$SSL_CERTIFICATE_KEY" ]; then
+    echo " (exists)"
+  else
+    echo " (missing)"
+  fi
+fi
+echo ""
+
+if [ ! -z "$DEBUG" ]; then
+
+  if [ -f "/opt/bitnami/nginx/conf/server_blocks/http_site.conf" ]; then
+    echo "content of /opt/bitnami/nginx/conf/server_blocks/http_site.conf"
+    echo "==============================================================="
+    cat /opt/bitnami/nginx/conf/server_blocks/http_site.conf
+    echo "==============================================================="
+  fi
+
+  if [ -f "/opt/bitnami/nginx/conf/server_blocks/https_site.conf" ]; then
+    echo "content of /opt/bitnami/nginx/conf/server_blocks/https_site.conf"
+    echo "==============================================================="
+    cat /opt/bitnami/nginx/conf/server_blocks/https_site.conf
+    echo "==============================================================="
+  fi
+
+  #tail -f /opt/bitnami/nginx/logs/* &
+fi
+
+# Call the base images' run.sh to start NGINX
+bash /opt/bitnami/scripts/nginx/run.sh
diff --git a/distribution/oam-controller/README.md b/distribution/oam-controller/README.md
new file mode 100644 (file)
index 0000000..a14e7ad
--- /dev/null
@@ -0,0 +1,63 @@
+# Wireless transport micro services (wt)
+
+This distribution uses the ONAP ODL image "onap/ccsdk-odl-fluorine-alpine-image" to create the ONAP WT Container.
+
+Configuration used by this container
+- Linux alpine as OS
+- ODL as single node or cluster node
+- Added bundles are Repository: 'ccsdk/features'/sdnr
+- ENTRYPOINT /opt/onap/ccsdk/bin/startSdnr.sh
+- ODLUX Login:
+    - ODL Default is user here: admin/admin
+
+## Parameters
+
+* SDNRWT true|false
+    - Switch on the SDNRWT feature.
+
+### Cluster specific
+
+* Node index, provided via host-name
+    - Format name-n
+    - n defines the host index. Starts with 0 .. N-1. Index of the cluster node that is started.
+
+* --env SDNC_REPLICAS=n
+    - n Number of cluster members.
+
+* --env PEER_ODL_CLUSTER="true"
+    - Set to any value for non GEO redundant setup.
+
+* --env ENABLE_ODL_CLUSTER="true"
+    - Mandatory to enable cluster configuration
+
+### Examples
+
+#### Start single node
+
+ docker run imageName
+
+#### Start three node clusters
+
+ docker run imageName --env NODE_INDEX="1" --env NODE_LIST="10.42.167.43 10.42.168.2 192.168.178.65"
+ docker run imageName --env NODE_INDEX="2" --env NODE_LIST="10.42.167.43 10.42.168.2 192.168.178.65"
+ docker run imageName --env NODE_INDEX="3" --env NODE_LIST="10.42.167.43 10.42.168.2 192.168.178.65"
+
+
+### Reference
+  [Opendaylight cluster configuration](https://docs.opendaylight.org/en/stable-nitrogen/getting-started-guide/common-features/clustering.html)
+
+## Container ports
+
+    docker run --detach --network="yaml_default" \
+      --link ccsdk_db_container:dbhost --link ccsdk_db_container:sdnctldb01 --link ccsdk_db_container:sdnctldb02 \
+      --publish 8181:8181 \
+      --publish 8185:8185 \
+      --publish 8085:8085 \
+      --publish 9200:9200 \
+      --env MYSQL_ROOT_PASSWORD=openECOMP1.0 \
+      --env SDNC_CONFIG_DIR=/opt/onap/ccsdk/data/properties \
+
+      --name sdnr \
+    "$IMAGE"
+
+
diff --git a/distribution/oam-controller/certs/certs.properties b/distribution/oam-controller/certs/certs.properties
new file mode 100644 (file)
index 0000000..0711ad1
--- /dev/null
@@ -0,0 +1,4 @@
+keys0.zip
+***********
+keys1.zip
+***********
diff --git a/distribution/oam-controller/certs/keys0.zip b/distribution/oam-controller/certs/keys0.zip
new file mode 100644 (file)
index 0000000..d1b99b0
Binary files /dev/null and b/distribution/oam-controller/certs/keys0.zip differ
diff --git a/distribution/oam-controller/certs/keys1.zip b/distribution/oam-controller/certs/keys1.zip
new file mode 100644 (file)
index 0000000..b046c79
Binary files /dev/null and b/distribution/oam-controller/certs/keys1.zip differ
diff --git a/distribution/oam-controller/pom.xml b/distribution/oam-controller/pom.xml
new file mode 100644 (file)
index 0000000..1df1832
--- /dev/null
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.o-ran-sc.ccsdk.distribution</groupId>
+    <artifactId>distribution-odlwt-alpine-standalone</artifactId>
+    <version>1.8.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>odlwt distribution</name>
+    <description>Creates patched opendaylight container with ONAP based wt features</description>
+
+    <organization>
+        <name>o-ran-sc</name>
+    </organization>
+
+    <properties>
+        <base.sdnc.image.repo>nexus3.onap.org:10001/onap/sdnc-image:2.6.0</base.sdnc.image.repo>
+        <base.image.repo>eclipse-temurin:21.0.5_11-jdk-alpine</base.image.repo>
+        <image.repo>10.20.6.10:30000</image.repo>
+        <image.name>o-ran-sc/sdnr-image</image.name>
+        <image.version>1.8.0-SNAPSHOT-latest</image.version>
+        <odl.karaf.version>0.21.2</odl.karaf.version>
+        <odl.aaa.version>0.20.8</odl.aaa.version>
+        <odl.ops4j.version>8.0.27</odl.ops4j.version>
+        <!--         <frinx.subtree.version>V4.20210208</frinx.subtree.version> -->
+        <ccsdk.features.version>${project.version}</ccsdk.features.version>
+        <ccsdk.feature.groupid>org.o-ran-sc.oam-controller.features.sdnr.wt</ccsdk.feature.groupid>
+        <ccsdk.feature.repopath>system/org/o-ran-sc/oam-controller/features/sdnr/wt</ccsdk.feature.repopath>
+        <ccsdk.project.version>${project.version}</ccsdk.project.version>
+        <ccsdk.build.timestamp>${maven.build.timestamp}</ccsdk.build.timestamp>
+        <!-- Below not used -->
+        <docker.buildArg.https_proxy>${https_proxy}</docker.buildArg.https_proxy>
+        <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+        <opendaylight.root>opt/opendaylight</opendaylight.root>
+        <docker.push.phase>deploy</docker.push.phase>
+        <docker.verbose>true</docker.verbose>
+
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>${ccsdk.feature.groupid}</groupId>
+            <artifactId>sdnr-wt-feature-aggregator-installer</artifactId>
+            <version>${ccsdk.features.version}</version>
+            <classifier>repo</classifier>
+            <type>zip</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <extensions>
+            <extension>
+                <!-- this extension is required by wagon in order to pass the proxy -->
+                <groupId>org.apache.maven.wagon</groupId>
+                <artifactId>wagon-http-lightweight</artifactId>
+                <version>2.2</version>
+            </extension>
+        </extensions>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.gmaven</groupId>
+                <artifactId>groovy-maven-plugin</artifactId>
+                <version>2.1.1</version>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>${basedir}/src/main/groovy/TagVersion.groovy</source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>2.6</version>
+                <executions>
+                    <execution>
+                        <id>copy-dockerfile</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                        <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/docker</directory>
+                                    <includes>
+                                        <include>Dockerfile</include>
+                                    </includes>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-scripts</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                        <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/opt/opendaylight/bin</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/resources</directory>
+                                    <includes>
+                                        <include>*.sh</include>
+                                    </includes>
+                                    <filtering>false</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-scripts4</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                        <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/scripts</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/scripts</directory>
+                                    <includes>
+                                        <include>.bashrc</include>
+                                        <include>startODL.sh</include>
+                                        <include>installCerts.py</include>
+                                    </includes>
+                                    <filtering>false</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-etc</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                        <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/etc</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/resources</directory>
+                                    <includes>
+                                        <include>*.properties</include>
+                                    </includes>
+                                    <filtering>false</filtering>
+                                </resource>
+                                <resource>
+                                    <directory>src/main/etc</directory>
+                                    <includes>
+                                        <include>*</include>
+                                    </includes>
+                                    <filtering>false</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-certs</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                        <!-- here the phase you need -->
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/certs</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/certs</directory>
+                                    <includes>
+                                        <include>*</include>
+                                    </includes>
+                                    <filtering>false</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-patches</id>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>                  
+                        <phase>validate</phase>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage/patches</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/patches</directory>
+                                    <includes>
+                                        <include>*</include>
+                                    </includes>
+                                    <filtering>false</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <!-- had to overwrite version because of a filelength bug during in unpack 
+                    goal which cuts filenames -->
+                <version>3.1.1</version>
+                <executions>
+                    <execution>
+                        <id>unpack features</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>unpack-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/docker-stage</outputDirectory>
+                            <excludeTransitive>true</excludeTransitive>
+                            <overWriteReleases>true</overWriteReleases>
+                            <overWriteSnapshots>true</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>get-odl-distribution</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.opendaylight.integration</groupId>
+                                    <artifactId>karaf</artifactId>
+                                    <version>${odl.karaf.version}</version>
+                                    <type>tar.gz</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${basedir}/target/docker-stage/odl</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                            <overWriteReleases>false</overWriteReleases>
+                            <overWriteSnapshots>true</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>
+                   <!-- <execution>
+                        <id>copy-with-alternalte-repo-2</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>com.highstreet-technologies.aaa</groupId>
+                                    <artifactId>aaa-authn-api</artifactId>
+                                    <version>${odl.aaa.version}</version>
+                                    <outputDirectory>${project.build.directory}/docker-stage/patches</outputDirectory>
+                                    <destFileName>aaa-authn-api-${odl.aaa.version}.jar</destFileName>
+                                    <excludes>*</excludes>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>com.highstreet-technologies.org.ops4j.pax.web</groupId>
+                                    <artifactId>pax-web-jetty</artifactId>
+                                    <version>${odl.ops4j.version}</version>
+                                    <outputDirectory>${project.build.directory}/docker-stage/patches</outputDirectory>
+                                    <destFileName>pax-web-jetty-${odl.ops4j.version}.jar</destFileName>
+                                    <excludes>*</excludes>
+                                </artifactItem>
+                            </artifactItems>
+                            <overWriteReleases>false</overWriteReleases>
+                            <overWriteSnapshots>true</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                        </configuration>
+                    </execution>  -->
+                </executions>
+
+            </plugin>
+
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <version>0.33.0</version>
+                <inherited>false</inherited>
+                <configuration>
+                    <images>
+                        <image>
+                            <name>${image.name}</name>
+                            <build>
+                                <cleanup>try</cleanup>
+                                <dockerFileDir>${basedir}/target/docker-stage</dockerFileDir>
+                                <dockerFile>Dockerfile</dockerFile>
+                                <tags>
+                                    <tag>${project.docker.latestminortag.version}</tag>
+                                    <tag>${project.docker.latestfulltag.version}</tag>
+                                    <tag>${project.docker.latesttagtimestamp.version}</tag>
+                                    <tag>${image.version}</tag>
+                                </tags>
+                            </build>
+                        </image>
+                    </images>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>generate-images</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>build</goal>
+                        </goals>
+                    </execution>
+
+                    <execution>
+                        <id>push-images</id>
+                        <phase>${docker.push.phase}</phase>
+                        <goals>
+                            <goal>build</goal>
+                            <goal>push</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/distribution/oam-controller/src/main/docker/Dockerfile b/distribution/oam-controller/src/main/docker/Dockerfile
new file mode 100644 (file)
index 0000000..9fab1ff
--- /dev/null
@@ -0,0 +1,99 @@
+FROM ${base.sdnc.image.repo} AS stage0
+FROM ${base.image.repo}
+
+ENV ODL_HOME /opt/opendaylight
+ENV IMAGEPATH ${base.image.repo}//${image.name}
+ENV IMAGENAMES "ONAP SDNC"//"SDNR Patches"
+ENV A1_ADAPTER_NORTHBOUND=false
+ENV CCSDKFEATUREVERSION ${ccsdk.features.version}
+ENV CCSDKFEATURE_SDNR_GROUPID ${ccsdk.feature.groupid}
+ENV FEATURES_SDNR ${ccsdk.feature.repopath}
+ENV SDNR_DM_REPO mvn:${CCSDKFEATURE_SDNR_GROUPID}/sdnr-wt-feature-aggregator/${CCSDKFEATUREVERSION}/xml/features, \
+    mvn:${CCSDKFEATURE_SDNR_GROUPID}/sdnr-wt-feature-aggregator-devicemanager-base/${CCSDKFEATUREVERSION}/xml/features, \
+    mvn:${CCSDKFEATURE_SDNR_GROUPID}/sdnr-wt-feature-aggregator-devicemanager/${CCSDKFEATUREVERSION}/xml/features, \
+    mvn:${CCSDKFEATURE_SDNR_GROUPID}/sdnr-wt-feature-aggregator-devicemanager-unm-generic/${CCSDKFEATUREVERSION}/xml/features, \
+    mvn:${CCSDKFEATURE_SDNR_GROUPID}/sdnr-wt-feature-aggregator-oauth/${CCSDKFEATUREVERSION}/xml/features
+
+ENV SDNR_FEATURES_BOOT_INITIAL odl-restconf-all,odl-netconf-topology,odl-netconf-callhome-ssh,odl-mdsal-all,odl-mdsal-apidocs,odl-daexim-all,odl-restconf-nb-rfc8040
+ENV JAVA_OPTS="-Xms512m -Xmx3g" 
+ENV ODL_ADMIN_PASSWORD "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"
+USER root
+
+# Install sudo and IP utilities
+RUN apk update && apk --no-cache add gcompat sudo iputils openssl bash unzip rsync nss python3
+# Enable wheel group
+RUN sed -e 's/# %wheel ALL=(ALL) NOPASSWD: ALL/%wheel ALL=(ALL) NOPASSWD: ALL/g' -i /etc/sudoers
+# Create odl user
+RUN addgroup -S odl && adduser -S odl -G odl
+RUN addgroup odl wheel
+
+# copy ODL
+COPY --chown=odl:odl odl/karaf-${odl.karaf.version} $ODL_HOME
+RUN ln -s /opt/opendaylight /opt/opendaylight/current
+
+# copy apps dependencies
+COPY --chown=odl:odl system /tmp/system
+RUN rsync -a --ignore-existing /tmp/system $ODL_HOME
+# copy patches
+#COPY patches/pax-web-jetty-${odl.ops4j.version}.jar $ODL_HOME/system/org/ops4j/pax/web/pax-web-jetty/${odl.ops4j.version}/
+#COPY patches/aaa-authn-api-${odl.aaa.version}.jar $ODL_HOME/system/org/opendaylight/aaa/aaa-authn-api/${odl.aaa.version}/
+# Add Frinx patches
+#COPY  --chown=odl:odl frinx/org/opendaylight/netconf $ODL_HOME/system/org/opendaylight/netconf/
+
+COPY --chown=odl:odl system/org/apache/kafka $ODL_HOME/system/org/apache/kafka
+COPY --chown=odl:odl system/com/github/luben $ODL_HOME/system/com/github/luben
+COPY --chown=odl:odl system/org/lz4 $ODL_HOME/system/org/lz4
+COPY --chown=odl:odl system/org/xerial/snappy $ODL_HOME/system/org/xerial/snappy
+
+# Patch WT Apps
+
+#RUN rm -r $ODL_HOME/$FEATURES_SDNR
+#COPY --chown=odl:odl $FEATURES_SDNR $ODL_HOME/$FEATURES_SDNR
+# Copy scripts
+COPY --from=stage0 --chown=odl:odl /opt/onap /opt/onap
+COPY --chown=odl:odl scripts/startODL.sh /opt/onap/sdnc/bin/
+COPY --chown=odl:odl scripts/installCerts.py /opt/onap/sdnc/bin/
+# Copy repository
+# visualVM configuration
+COPY --chown=odl:odl etc $ODL_HOME/etc
+# copy bash init script into container
+COPY --chown=odl:odl scripts/.bashrc /home/odl/
+
+#Adjust repositories
+RUN sed -i -e "\|featuresRepositories|s|$|, ${SDNR_DM_REPO}|"  $ODL_HOME/etc/org.apache.karaf.features.cfg
+#Adjust featuresboot
+RUN sed -i -e "\|featuresBoot *=|s|$|,${SDNR_FEATURES_BOOT_INITIAL}|"  $ODL_HOME/etc/org.apache.karaf.features.cfg
+
+RUN chmod 775 /opt/onap/sdnc/bin/*.sh
+#RUN apk add curl
+#back to user odl
+
+# Install ssl and java certificates
+ENV JAVA_SECURITY_DIR /etc/ssl/certs/java
+ENV SDNC_STORE_DIR /opt/onap/sdnc/data/stores
+
+COPY --from=stage0 $SDNC_STORE_DIR/truststoreONAPall.jks $JAVA_SECURITY_DIR/
+COPY --from=stage0 $SDNC_STORE_DIR/truststoreONAPall.jks $SDNC_STORE_DIR/
+RUN keytool -importkeystore -srckeystore $JAVA_SECURITY_DIR/truststoreONAPall.jks -srcstorepass changeit -destkeystore $JAVA_SECURITY_DIR/cacerts  -deststorepass changeit -noprompt
+RUN keytool -importkeystore -srckeystore $JAVA_SECURITY_DIR/truststoreONAPall.jks -srcstorepass changeit -destkeystore /opt/java/openjdk/lib/security/cacerts  -deststorepass changeit -noprompt
+RUN mkdir $ODL_HOME/certs
+RUN chown -R odl:odl /opt
+
+
+ENV SDNC_SECUREPORT=8443
+ENV SDNC_KEYPASS=changeit2
+#${sdnc.keypass}
+ENV SDNC_KEYSTORE=org.onap.sdnc.p12
+RUN echo org.osgi.service.http.secure.enabled=true >> $ODL_HOME/etc/custom.properties
+RUN echo org.osgi.service.http.port.secure=$SDNC_SECUREPORT >> $ODL_HOME/etc/custom.properties
+RUN echo org.ops4j.pax.web.ssl.keystore=$SDNC_STORE_DIR/truststoreONAPall.jks >> $ODL_HOME/etc/custom.properties
+RUN echo org.ops4j.pax.web.ssl.password=$SDNC_KEYPASS >> $ODL_HOME/etc/custom.properties
+RUN echo org.ops4j.pax.web.ssl.keypassword=$SDNC_KEYPASS >> $ODL_HOME/etc/custom.properties
+
+USER odl
+WORKDIR /opt/opendaylight
+
+CMD [ "/bin/bash" ]
+ENTRYPOINT [ "/opt/onap/sdnc/bin/startODL.sh" ]
+EXPOSE 8181 1090 1099
+
diff --git a/distribution/oam-controller/src/main/etc/oauth-aaa-app-config.xml b/distribution/oam-controller/src/main/etc/oauth-aaa-app-config.xml
new file mode 100644 (file)
index 0000000..65e34db
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0" ?>
+<!--
+  ~ ============LICENSE_START=======================================================
+  ~ ONAP : ccsdk features
+  ~ ================================================================================
+  ~ Copyright (C) 2021 highstreet technologies GmbH Intellectual Property.
+  ~ All rights reserved.
+  ~ ================================================================================
+  ~ 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.
+  ~ ============LICENSE_END=======================================================
+  ~
+  -->
+
+<shiro-configuration xmlns="urn:opendaylight:aaa:app:config">
+
+
+    <main>
+        <pair-key>tokenAuthRealm</pair-key>
+        <!--<pair-value>org.opendaylight.aaa.shiro.realm.TokenAuthRealm</pair-value>-->
+        <pair-value>org.onap.ccsdk.features.sdnr.wt.oauthprovider.OAuth2Realm</pair-value>
+    </main>
+
+    <main>
+        <pair-key>securityManager.realms</pair-key>
+        <pair-value>$tokenAuthRealm</pair-value>
+    </main>
+    <!-- Used to support OAuth2 use case. -->
+    <main>
+        <pair-key>anyroles</pair-key>
+        <pair-value>org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters.AnyRoleHttpAuthenticationFilter</pair-value>
+    </main>
+    <main>
+        <pair-key>authcBearer</pair-key>
+<!--        <pair-value>org.apache.shiro.web.filter.authc.BearerHttpAuthenticationFilter</pair-value>-->
+        <pair-value>org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters.BearerAndBasicHttpAuthenticationFilter</pair-value>
+    </main>
+
+    <!-- in order to track AAA challenge attempts -->
+    <main>
+        <pair-key>accountingListener</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.filters.AuthenticationListener</pair-value>
+    </main>
+    <main>
+        <pair-key>securityManager.authenticator.authenticationListeners</pair-key>
+        <pair-value>$accountingListener</pair-value>
+    </main>
+
+    <!-- Model based authorization scheme supporting RBAC for REST endpoints -->
+    <main>
+        <pair-key>dynamicAuthorization</pair-key>
+        <pair-value>org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters.CustomizedMDSALDynamicAuthorizationFilter</pair-value>
+    </main>
+
+
+    <urls>
+        <pair-key>/**/operations/cluster-admin**</pair-key>
+        <pair-value>authcBearer, roles[admin]</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/**/v1/**</pair-key>
+        <pair-value>authcBasic, roles[admin]</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/**/config/aaa*/**</pair-key>
+        <pair-value>authcBasic, roles[admin]</pair-value>
+    </urls>
+     <urls>
+        <pair-key>/oauth/**</pair-key>
+        <pair-value>anon</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/odlux/**</pair-key>
+        <pair-value>anon</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/apidoc/**</pair-key>
+        <pair-value>authcBasic</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/rests/**</pair-key>
+        <pair-value>authcBearer, anyroles["admin,provision"]</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/**</pair-key>
+        <pair-value>authcBearer, roles[admin]</pair-value>
+    </urls>
+</shiro-configuration>
diff --git a/distribution/oam-controller/src/main/etc/oauth-provider.config.json b/distribution/oam-controller/src/main/etc/oauth-provider.config.json
new file mode 100644 (file)
index 0000000..e7c8d47
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "tokenSecret": "secret",
+    "tokenIssuer": "onap.sdnc",
+    "publicUrl": "http://172.18.0.4:8080",
+    "redirectUri": "/odlux/index.html#/oauth?token=",
+    "supportOdlUsers": "true",
+    "providers": [
+{
+                       "id": "identity",
+                       "type": "KEYCLOAK",
+                       "url": "https://identity.smo-int-1.t3.lab.osn-lab.com",
+                       "clientId": "odlux.app",
+                       "secret": "2a64fdca-c205-4b52-9f58-195ccc142ddb",
+                       "scope": "openid",
+                       "title": "ONAP-IDENTITY",
+                       "roleMapping": {
+                               "administration": "admin"
+                       },
+                       "realmName": "onap",
+            "trustAll": "true"
+               }]
+}
diff --git a/distribution/oam-controller/src/main/etc/org.apache.karaf.management.cfg b/distribution/oam-controller/src/main/etc/org.apache.karaf.management.cfg
new file mode 100644 (file)
index 0000000..b832e4f
--- /dev/null
@@ -0,0 +1,123 @@
+
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You 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.
+#
+################################################################################
+
+#
+# The properties in this file define the configuration of Apache Karaf's JMX Management
+#
+
+#
+# Port number for RMI registry connection
+#
+rmiRegistryPort = 1099
+
+#
+# Host for RMI registry
+#
+rmiRegistryHost = 0.0.0.0
+
+#
+# Port number for RMI server connection
+#
+rmiServerPort = 44444
+
+#
+# Host for RMI server
+#
+rmiServerHost = 0.0.0.0
+
+#
+# Name of the JAAS realm used for authentication
+#
+jmxRealm = karaf
+
+#
+# The service URL for the JMXConnectorServer
+#
+serviceUrl = service:jmx:rmi://${rmiServerHost}:${rmiServerPort}/jndi/rmi://${rmiRegistryHost}:${rmiRegistryPort}/karaf-${karaf.name}
+
+#
+# Whether any threads started for the JMXConnectorServer should be started as daemon threads
+#
+daemon = true
+
+#
+# Whether the JMXConnectorServer should be started in a separate thread
+#
+threaded = true
+
+#
+# The ObjectName used to register the JMXConnectorServer
+#
+objectName = connector:name=rmi
+
+#
+# Timeout to lookup for the keystore in case of SSL authentication usage
+#
+#keyStoreAvailabilityTimeout = 5000
+
+#
+# The type of authentication
+#
+authenticatorType = password
+
+#
+# Enable or not SSL/TLS
+#
+secured = false
+
+#
+# Secure algorithm to use
+#
+#secureAlgorithm = default
+
+#
+# Secure protocol to use
+#
+#secureProtocol = TLS
+
+#
+# Keystore to use for secure mode
+#
+#keyStore = karaf.ks
+
+#
+# Alias of the key to use in the keystore
+#
+#keyAlias = karaf
+
+#
+# Truststore to use for secure mode
+#
+#trustStore = karaf.ts
+
+#
+# Create the JMX RMI registry
+#
+#createRmiRegistry = true
+
+#
+# Locate the JMX RMI registry
+#
+#locateRmiRegistry = true
+
+#
+# Locate an existing MBean server if possible (usefull when Karaf is embedded)
+#
+#locateExistingMBeanServerIfPossible = true
diff --git a/distribution/oam-controller/src/main/groovy/TagVersion.groovy b/distribution/oam-controller/src/main/groovy/TagVersion.groovy
new file mode 100644 (file)
index 0000000..68a8b78
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CCSDK
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ *                             reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.ccsdk.distribution
+
+
+def versionArray;
+if ( project.properties['ccsdk.project.version'] != null ) {
+       versionArray = project.properties['ccsdk.project.version'].split('\\.');
+}
+
+if ( project.properties['ccsdk.project.version'].endsWith("-SNAPSHOT") ) {
+       patchArray = versionArray[2].split('-');
+       project.properties['project.docker.latestminortag.version']=versionArray[0] + '.' + versionArray[1] + "-SNAPSHOT-latest";
+       project.properties['project.docker.latestfulltag.version']=versionArray[0] + '.' + versionArray[1] + '.' + patchArray[0] + "-SNAPSHOT-latest";
+       project.properties['project.docker.latesttagtimestamp.version']=versionArray[0] + '.' + versionArray[1] + '.' + patchArray[0] + "-SNAPSHOT-"+project.properties['ccsdk.build.timestamp'];
+} else {
+       project.properties['project.docker.latestminortag.version']=versionArray[0] + '.' + versionArray[1] + "-STAGING-latest";
+       project.properties['project.docker.latestfulltag.version']=versionArray[0] + '.' + versionArray[1] + '.' + versionArray[2] + "-STAGING-latest";
+       project.properties['project.docker.latesttagtimestamp.version']=versionArray[0] + '.' + versionArray[1] + '.' + versionArray[2] + "-STAGING-"+project.properties['ccsdk.build.timestamp'];
+}
diff --git a/distribution/oam-controller/src/main/scripts/installCerts.py b/distribution/oam-controller/src/main/scripts/installCerts.py
new file mode 100755 (executable)
index 0000000..70950e2
--- /dev/null
@@ -0,0 +1,386 @@
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2019 Nordix Foundation.
+# ================================================================================
+#  extended by highstreet technologies GmbH (c) 2020
+#  Copyright (c) 2021 Nokia 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+
+# coding=utf-8
+import os
+import sys
+import re
+import http.client
+import base64
+import time
+import zipfile
+import shutil
+import subprocess
+import logging
+
+odl_home = os.environ['ODL_HOME']
+log_directory = odl_home + '/data/log/'
+log_file = log_directory + 'installCerts.log'
+with open(os.path.join(log_directory, 'installCerts.log'), 'w') as fp:
+    pass
+log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+if not os.path.exists(log_directory):
+    os.makedirs(log_directory)
+logging.basicConfig(filename=log_file,level=logging.DEBUG,filemode='w',format=log_format)
+print ('Start cert provisioning. Log file: ' + log_file);
+
+Path = "/tmp"
+if "ODL_CERT_DIR" in os.environ:
+    Path = os.environ['ODL_CERT_DIR']
+
+zipFileList = []
+
+username = os.environ['ODL_ADMIN_USERNAME']
+password = os.environ['ODL_ADMIN_PASSWORD']
+TIMEOUT=1000
+INTERVAL=30
+timePassed=0
+
+postKeystore= "/rests/operations/netconf-keystore:add-keystore-entry"
+postPrivateKey= "/rests/operations/netconf-keystore:add-private-key"
+postTrustedCertificate= "/rests/operations/netconf-keystore:add-trusted-certificate"
+
+truststore_pass_file = Path + '/truststore.pass'
+truststore_file = Path + '/truststore.jks'
+
+keystore_pass_file = Path + '/keystore.pass'
+keystore_file = Path + '/keystore.jks'
+
+jks_files = [truststore_pass_file, keystore_pass_file, keystore_file, truststore_file]
+
+envOdlFeaturesBoot='ODL_FEATURES_BOOT'
+# Strategy sli-api is default
+certreadyCmd="POST"
+certreadyUrl="/rests/operations/SLI-API:healthcheck"
+
+if "SDNRWT" in os.environ: 
+    sdnrWt = os.environ['SDNRWT']
+    if sdnrWt == "true":
+        certreadyCmd="GET"
+        certreadyUrl="/rests/data/network-topology:network-topology"
+logging.info('ODL ready strategy with command %s and url %s', certreadyCmd, certreadyUrl)
+
+odl_port = 8181
+cred_string = username + ":" + password
+headers = {'Authorization':'Basic %s' % base64.b64encode(cred_string.encode()).decode(),
+           'X-FromAppId': 'csit-sdnc',
+           'X-TransactionId': 'csit-sdnc',
+           'Accept':"application/json",
+           'Content-type':"application/yang-data+json"}
+
+def readFile(folder, file):
+    key = open(Path + "/" + folder + "/" + file, "r")
+    fileRead = key.read()
+    key.close()
+    fileRead = "\n".join(fileRead.splitlines())
+    return fileRead
+
+def readTrustedCertificate(folder, file):
+    listCert = list()
+    caPem = ""
+    startCa = False
+    key = open(folder + "/" + file, "r")
+    lines = key.readlines()
+    for line in lines:
+        if not "BEGIN CERTIFICATE" in line and not "END CERTIFICATE" in line and startCa:
+            caPem += line
+        elif "BEGIN CERTIFICATE" in line:
+            startCa = True
+            caPem += line
+        elif "END CERTIFICATE" in line:
+            startCa = False
+            caPem += line
+            listCert.append(caPem)
+            caPem = ""
+    return listCert
+
+def makeKeystoreKey(clientKey, count):
+    odl_private_key = "ODL_private_key_%d" %count
+
+    json_keystore_key='{{\"input\": {{ \"key-credential\": {{\"key-id\": \"{odl_private_key}\", \"private-key\" : ' \
+                      '\"{clientKey}\",\"passphrase\" : \"\"}}}}}}'.format(
+        odl_private_key=odl_private_key,
+        clientKey=clientKey)
+
+    return json_keystore_key
+
+def makePrivateKey(clientKey, clientCrt, certList, count):
+    caPem = ""
+    if certList:
+        for cert in certList:
+            caPem += '\"%s\",' % cert
+        caPem = caPem.rsplit(',', 1)[0]
+    odl_private_key="ODL_private_key_%d" %count
+
+    json_private_key='{{\"input\": {{ \"private-key\":{{\"name\": \"{odl_private_key}\", \"data\" : ' \
+                     '\"{clientKey}\",\"certificate-chain\":[\"{clientCrt}\",{caPem}]}}}}}}'.format(
+        odl_private_key=odl_private_key,
+        clientKey=clientKey,
+        clientCrt=clientCrt,
+        caPem=caPem)
+
+    return json_private_key
+
+def makeTrustedCertificate(certList, count):
+    number = 0
+    json_cert_format = ""
+    for cert in certList:
+        cert_name = "xNF_CA_certificate_%d_%d" %(count, number)
+        json_cert_format += '{{\"name\": \"{trusted_name}\",\"certificate\":\"{cert}\"}},\n'.format(
+            trusted_name=cert_name,
+            cert=cert.strip())
+        number += 1
+
+    json_cert_format = json_cert_format.rsplit(',', 1)[0]
+    json_trusted_cert='{{\"input\": {{ \"trusted-certificate\": [{certificates}]}}}}'.format(
+        certificates=json_cert_format)
+    return json_trusted_cert
+
+
+def makeRestconfPost(conn, json_file, apiCall):
+    req = conn.request("POST", apiCall, json_file, headers=headers)
+    res = conn.getresponse()
+    res.read()
+    if res.status != 200 and res.status != 204:
+        logging.error("Error here, response back wasnt 200: Response was : %d , %s" % (res.status, res.reason))
+        writeCertInstallStatus("NOTOK")
+    else:
+        logging.debug("Response :%s Reason :%s ",res.status, res.reason)
+
+def extractZipFiles(zipFileList, count):
+    for zipFolder in zipFileList:
+        try:
+                with zipfile.ZipFile(Path + "/" + zipFolder.strip(),"r") as zip_ref:
+                    zip_ref.extractall(Path)
+                folder = zipFolder.rsplit(".")[0]
+                processFiles(folder, count)
+        except Exception as e:
+                logging.error("Error while extracting zip file(s). Exiting Certificate Installation.")
+                logging.info("Error details : %s" % e)
+                writeCertInstallStatus("NOTOK")
+
+def processFiles(folder, count):
+    logging.info('Process folder: %d %s', count, folder)
+    for file in os.listdir(Path + "/" + folder):
+        if os.path.isfile(Path + "/" + folder + "/" + file.strip()):
+            if ".key" in file:
+                clientKey = readFile(folder, file.strip())
+            elif "trustedCertificate" in file:
+                certList = readTrustedCertificate(Path + "/" + folder, file.strip())
+            elif ".crt" in file:
+                clientCrt = readFile(folder, file.strip())
+        else:
+            logging.error("Could not find file %s" % file.strip())
+            writeCertInstallStatus("NOTOK")
+    shutil.rmtree(Path + "/" + folder)
+    post_content(clientKey, clientCrt, certList, count)
+
+def post_content(clientKey, clientCrt, certList, count):
+    logging.info('Post content: %d', count)
+    conn = http.client.HTTPConnection("localhost",odl_port)
+
+    if clientKey:
+        json_keystore_key = makeKeystoreKey(clientKey, count)
+        logging.debug("Posting private key in to ODL keystore")
+        makeRestconfPost(conn, json_keystore_key, postKeystore)
+
+    if certList:
+        json_trusted_cert = makeTrustedCertificate(certList, count)
+        logging.debug("Posting trusted cert list in to ODL")
+        makeRestconfPost(conn, json_trusted_cert, postTrustedCertificate)
+
+    if clientKey and clientCrt and certList:
+        json_private_key = makePrivateKey(clientKey, clientCrt, certList, count)
+        logging.debug("Posting the cert in to ODL")
+        makeRestconfPost(conn, json_private_key, postPrivateKey)
+
+
+def makeHealthcheckCall(headers, timePassed):
+    connected = False
+    # WAIT 10 minutes maximum and test every 30 seconds if HealthCheck API is returning 200
+    while timePassed < TIMEOUT:
+        try:
+            conn = http.client.HTTPConnection("localhost",odl_port)
+            req = conn.request(certreadyCmd, certreadyUrl,headers=headers)
+            res = conn.getresponse()
+            res.read()
+            httpStatus = res.status
+            if httpStatus == 200:
+                logging.debug("Healthcheck Passed in %d seconds." %timePassed)
+                connected = True
+                break
+            else:
+                logging.debug("Sleep: %d seconds before testing if Healthcheck worked. Total wait time up now is: %d seconds. Timeout is: %d seconds. Problem code was: %d" %(INTERVAL, timePassed, TIMEOUT, httpStatus))
+        except:
+            logging.error("Cannot execute REST call. Sleep: %d seconds before testing if Healthcheck worked. Total wait time up now is: %d seconds. Timeout is: %d seconds." %(INTERVAL, timePassed, TIMEOUT))
+        timePassed = timeIncrement(timePassed)
+
+    if timePassed > TIMEOUT:
+        logging.error("TIME OUT: Healthcheck not passed in  %d seconds... Could cause problems for testing activities..." %TIMEOUT)
+        writeCertInstallStatus("NOTOK")
+
+    return connected
+
+
+def timeIncrement(timePassed):
+    time.sleep(INTERVAL)
+    timePassed = timePassed + INTERVAL
+    return timePassed
+
+
+def get_pass(file_name):
+    try:
+        with open(file_name, 'r') as file_obj:
+            password = file_obj.read().strip()
+        return "'{}'".format(password)
+    except Exception as e:
+        logging.error("Error occurred while fetching password : %s", e)
+        writeCertInstallStatus("NOTOK")
+
+def cleanup():
+    for file in os.listdir(Path):
+        if os.path.isfile(Path + '/' + file):
+            logging.debug("Cleaning up the file %s", Path + '/'+ file)
+            os.remove(Path + '/'+ file)
+
+
+def jks_to_p12(file, password):
+    """Converts jks format into p12"""
+    try:
+        certList = []
+        key = None
+        cert = None
+        if (file.endswith('.jks')):
+             p12_file = file.replace('.jks', '.p12')
+             jks_cmd = 'keytool -importkeystore -srckeystore {src_file} -destkeystore {dest_file} -srcstoretype JKS -srcstorepass {src_pass} -deststoretype PKCS12 -deststorepass {dest_pass}'.format(src_file=file, dest_file=p12_file, src_pass=password, dest_pass=password)
+             logging.debug("Converting %s into p12 format", file)
+             os.system(jks_cmd)
+             file = p12_file
+             return file
+    except Exception as e:
+        logging.error("Error occurred while converting jks to p12 format : %s", e)
+        writeCertInstallStatus("NOTOK")
+
+
+def make_cert_chain(cert_chain, pattern):
+    cert_list = []
+    if cert_chain:
+        cert_chain = cert_chain.decode('utf-8')
+        matches = re.findall(pattern, cert_chain, re.DOTALL | re.MULTILINE)
+        for cert in matches:
+            cert_list.append(cert.strip())
+        return cert_list
+    else:
+        logging.debug(" Certificate Chain empty: %s " % cert_chain)
+
+
+def process_jks_files(count):
+    ca_cert_list = []
+    logging.info("Processing JKS files found in %s directory " % Path)
+    try:
+        if all([os.path.isfile(f) for f in jks_files]):
+            keystore_pass = get_pass(keystore_pass_file)
+            keystore_file_p12 = jks_to_p12(keystore_file, keystore_pass)
+
+            client_key_cmd = 'openssl pkcs12 -in {src_file} -nocerts -nodes -passin pass:{src_pass}'.format(
+                src_file=keystore_file_p12, src_pass=keystore_pass)
+            client_crt_cmd = 'openssl pkcs12 -in {src_file} -clcerts -nokeys  -passin pass:{src_pass}'.format(
+                src_file=keystore_file_p12, src_pass=keystore_pass)
+
+            truststore_pass = get_pass(truststore_pass_file)
+            truststore_p12 = jks_to_p12(truststore_file, truststore_pass)
+
+            trust_cert_cmd = 'openssl pkcs12 -in {src_file} -cacerts -nokeys -passin pass:{src_pass} '.format(
+                src_file=truststore_p12, src_pass=truststore_pass)
+
+            key_pattern = r'(?<=-----BEGIN PRIVATE KEY-----).*?(?=-----END PRIVATE KEY-----)'
+            client_key = subprocess.check_output(client_key_cmd, shell=True)
+            if client_key:
+                client_key = make_cert_chain(client_key, key_pattern)[0]
+                logging.debug("Key Ok")
+
+            cert_pattern = r'(?<=-----BEGIN CERTIFICATE-----).*?(?=-----END CERTIFICATE-----)'
+            client_cert = subprocess.check_output(client_crt_cmd, shell=True)
+            if client_cert:
+                client_cert = make_cert_chain(client_cert, cert_pattern)[0]
+                logging.debug("Client Cert Ok")
+
+            ca_cert = subprocess.check_output(trust_cert_cmd, shell=True)
+            if ca_cert:
+                ca_cert_list = make_cert_chain(ca_cert, cert_pattern)
+                logging.debug("CA Cert Ok")
+
+            if client_key and client_cert and ca_cert:
+                post_content(client_key, client_cert, ca_cert_list, count)
+        else:
+            logging.debug("No JKS files found in %s directory" % Path)
+    except subprocess.CalledProcessError as err:
+        print("CalledProcessError Execution of OpenSSL command failed: %s" % err)
+        writeCertInstallStatus("NOTOK")
+    except Exception as e:
+        logging.error("UnExpected Error while processing JKS files at {0}, Caused by: {1}".format(Path, e))
+        writeCertInstallStatus("NOTOK")
+
+def readCertProperties():
+    '''
+    This function searches for manually copied zip file
+    containing certificates. This is required as part
+    of backward compatibility.
+    If not foud, it searches for jks certificates.
+    '''
+    connected = makeHealthcheckCall(headers, timePassed)
+    logging.info('Connected status: %s', connected)
+    if connected:
+        count = 0
+        if os.path.isfile(Path + "/certs.properties"):
+            with open(Path + "/certs.properties", "r") as f:
+                for line in f:
+                    if not "*****" in line:
+                        zipFileList.append(line)
+                    else:
+                        extractZipFiles(zipFileList, count)
+                        count += 1
+                        del zipFileList[:]
+        else:
+            logging.debug("No certs.properties/zip files exist at: " + Path)
+            logging.info("Processing any  available jks/p12 files under cert directory")
+            process_jks_files(count)
+    else:
+        logging.info('Connected status: %s', connected)
+        logging.info('Stopping SDNR due to inability to install certificates')
+        writeCertInstallStatus("NOTOK")
+        
+def writeCertInstallStatus(installStatus):
+    if installStatus == "NOTOK":
+        with open(os.path.join(log_directory, 'INSTALLCERTSFAIL'), 'w') as fp:
+            pass
+            sys.exit(1)
+    elif installStatus == "OK":
+        with open(os.path.join(log_directory, 'INSTALLCERTSPASS'), 'w') as fp:
+            pass
+            sys.exit(0)
+
+readCertProperties()
+logging.info('Cert installation ending')
+writeCertInstallStatus("OK")
+
diff --git a/distribution/oam-controller/src/main/scripts/startODL.sh b/distribution/oam-controller/src/main/scripts/startODL.sh
new file mode 100755 (executable)
index 0000000..197cae5
--- /dev/null
@@ -0,0 +1,456 @@
+#!/bin/sh
+###
+# ============LICENSE_START=======================================================
+# SDN-C
+# ================================================================================
+# Copyright (C) 2020 Samsung Electronics
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2020 Highstreet Technologies
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+# A single entry point script that can be used in Kubernetes based deployments (via OOM) and standalone docker deployments.
+# Please see https://wiki.onap.org/display/DW/startODL.sh+-+Important+Environment+variables+and+their+description for more details
+
+# Functions
+
+# Test if repository exists, like this mvn:org.onap.ccsdk.features.sdnr.wt/sdnr-wt-devicemanager-oran-feature/0.7.2/xml/features
+# $1 repository
+isRepoExisting() {
+  REPO=$(echo "$1" | sed -E "s#mvn:(.*)/xml/features\$#\1#")
+  OIFS="$IFS"
+  IFS='/'
+  set parts $REPO
+  IFS="$OIFS"
+  path="$ODL_HOME/system/$(echo "$2" | tr '.' '/')/$3/$4"
+  [ -d "$path" ]
+}
+
+# Add features repository to karaf featuresRepositories configuration
+# $1 repositories to be added
+addRepository() {
+  CFG=$ODL_FEATURES_BOOT_FILE
+  ORIG=$CFG.orig
+  if isRepoExisting "$1" ; then
+    printf "%s\n" "Add repository: $1"
+    sed -i "\|featuresRepositories|s|$|, $1|" "$CFG"
+  else
+    printf "%s\n" "Repo does not exist: $1"
+  fi
+}
+
+# Append features to karaf boot feature configuration
+# $1 additional feature to be added
+# $2 repositories to be added (optional)
+addToFeatureBoot() {
+  CFG=$ODL_FEATURES_BOOT_FILE
+  ORIG=$CFG.orig
+  if [ -n "$2" ] ; then
+    printf "%s\n" "Add repository: $2"
+    mv "$CFG" "$ORIG"
+    sed -e "\|featuresRepositories|s|$|,$2|" "$ORIG" > "$CFG"
+  fi
+  printf "%s\n" "Add boot feature: $1"
+  mv "$CFG" "$ORIG"
+  sed -e "\|featuresBoot *=|s|$|,$1|" "$ORIG" > "$CFG"
+}
+
+# Append features to karaf boot feature configuration
+# $1 search pattern
+# $2 replacement
+replaceFeatureBoot() {
+  CFG="$ODL_HOME"/etc/org.apache.karaf.features.cfg
+  ORIG=$CFG.orig
+  printf "%s %s\n" "Replace boot feature $1 with: $2"
+  sed -i "/featuresBoot/ s/$1/$2/g" "$CFG"
+}
+
+# Remove all sdnc specific features
+cleanupFeatureBoot() {
+  printf "Remove northbound bootfeatures \n"
+  sed -i "/featuresBoot/ s/,ccsdk-sli-core-all.*$//g" "$ODL_FEATURES_BOOT_FILE"
+}
+
+initialize_sdnrdb() {
+  printf "SDN-R Database Initialization"
+  INITCMD="$JAVA_HOME/bin/java -jar "
+  FN=$(find "$ODL_HOME/system" -name "sdnr-wt-data-provider-setup-*.jar")
+  INITCMD="${INITCMD} ${FN} $SDNRDBCOMMAND"
+  printf "%s\n" "Execute: $INITCMD"
+  n=0
+  until [ $n -ge 5 ] ; do
+    $INITCMD
+    ret=$?
+    if [ $ret -eq 0 ] ; then
+      break;
+    fi
+    n=$((n+1))
+    sleep 15
+  done
+  return $ret
+}
+
+install_sdnrwt_features() {
+  # Repository setup provided via sdnc dockerfile
+  if $SDNRWT; then
+    if $SDNRONLY; then
+      cleanupFeatureBoot
+    fi
+    if $SDNRUNMDM; then
+      addToFeatureBoot "$SDNRDM_UNM_BOOTFEATURES"
+    else
+      addToFeatureBoot "$SDNRDM_BOOTFEATURES"
+  #    if ! $SDNRDM; then
+  #      addToFeatureBoot "$SDNRODLUX_BOOTFEATURES"
+  #    fi
+      if $SDNR_NETCONF_CALLHOME_ENABLED; then
+        addToFeatureBoot "$SDNR_NETCONF_CALLHOME_FEATURE"
+      fi
+    fi
+  fi
+}
+install_sdnr_oauth_features() {
+  addToFeatureBoot "$SDNROAUTH_BOOTFEATURES"
+}
+install_sdnr_northbound_features() {
+  addToFeatureBoot "$SDNR_NORTHBOUND_BOOTFEATURES"
+}
+install_a1_northbound_features() {
+  addToFeatureBoot "$A1_ADAPTER_NORTHBOUND_BOOTFEATURES"
+}
+# Reconfigure ODL from default single node configuration to cluster
+
+enable_odl_cluster() {
+  if [ -z "$SDNC_REPLICAS" ]; then
+     printf "SDNC_REPLICAS is not configured in Env field"
+     exit
+  fi
+
+  # ODL NETCONF setup
+  printf "Installing Opendaylight cluster features for mdsal and netconf\n"
+
+  #Be sure to remove feature odl-netconf-connector-all from list
+  replaceFeatureBoot "odl-netconf-connector-all,"
+
+  printf "Installing Opendaylight cluster features\n"
+  replaceFeatureBoot odl-netconf-topology odl-netconf-clustered-topology
+  replaceFeatureBoot odl-mdsal-all odl-mdsal-all,odl-mdsal-clustering
+  addToFeatureBoot odl-jolokia
+  #${ODL_HOME}/bin/client feature:install odl-mdsal-clustering
+  #${ODL_HOME}/bin/client feature:install odl-jolokia
+
+  # ODL Cluster or Geo cluster configuration
+
+  printf "Update cluster information statically\n"
+  fqdn=$(hostname -f)
+  printf "%s\n" "Get current fqdn ${fqdn}"
+
+  # Extract node index using first digit after "-"
+  # Example 2 from "sdnr-2.logo.ost.das.r32.com"
+  node_index=$(echo "${fqdn}" | sed -r 's/.*-([0-9]).*/\1/g')
+  member_offset=1
+
+  if $GEO_ENABLED; then
+    printf "This is a Geo cluster\n"
+
+    if [ -z "$IS_PRIMARY_CLUSTER" ] || [ -z "$MY_ODL_CLUSTER" ] || [ -z "$PEER_ODL_CLUSTER" ]; then
+     printf "IS_PRIMARY_CLUSTER, MY_ODL_CLUSTER and PEER_ODL_CLUSTER must all be configured in Env field\n"
+     return
+    fi
+
+    if $IS_PRIMARY_CLUSTER; then
+       PRIMARY_NODE=${MY_ODL_CLUSTER}
+       SECONDARY_NODE=${PEER_ODL_CLUSTER}
+    else
+       PRIMARY_NODE=${PEER_ODL_CLUSTER}
+       SECONDARY_NODE=${MY_ODL_CLUSTER}
+       member_offset=4
+    fi
+
+    node_list="${PRIMARY_NODE} ${SECONDARY_NODE}"
+
+    "${SDNC_BIN}"/configure_geo_cluster.sh $((node_index+member_offset)) "${node_list}"
+  else
+    printf "This is a local cluster\n"
+    i=0
+    node_list=""
+    # SERVICE_NAME and NAMESPACE are used to create cluster node names and are provided via Helm charts in OOM environment
+    if [ ! -z "$SERVICE_NAME" ] && [ ! -z "$NAMESPACE" ]; then
+       # Extract node name minus the index
+       # Example sdnr from "sdnr-2.logo.ost.das.r32.com"
+       node_name=$(echo "${fqdn}" | sed 's/-[0-9].*$//g')
+       while [ $i -lt "$SDNC_REPLICAS" ]; do
+         node_list="${node_list} ${node_name}-$i.${SERVICE_NAME}-cluster.${NAMESPACE}"
+         i=$(($i + 1))
+       done
+       "${ODL_HOME}"/bin/configure_cluster.sh $((node_index+1)) "${node_list}"
+    elif [ -z "$SERVICE_NAME" ] && [ -z "$NAMESPACE" ]; then
+      # Hostname is used in Standalone environment to create cluster node names
+       while [ $i -lt "$SDNC_REPLICAS" ]; do
+         #assemble node list by replacing node-index in hostname with "i"
+         node_name=$(echo "${fqdn}" | sed -r "s/-[0-9]/-$i/g")
+         node_list="${node_list} ${node_name}"
+         i=$(($i + 1))
+       done
+       "${ODL_HOME}"/bin/configure_cluster.sh $((node_index+1)) "${node_list}"
+    else
+       printf "Unhandled cluster scenario. Terminating the container\n"
+       printf "Any one of the below 2 conditions should be satisfied for successfully enabling cluster mode : \n"
+       printf "1. OOM Environment - Both SERVICE_NAME and NAMESPACE environment variables have to be set.\n"
+       printf "2. Docker (standalone) Environment - Neither of SERVICE_NAME and NAMESPACE have to be set.\n"
+       printf "Current configuration - SERVICE_NAME = $SERVICE_NAME  NAMESPACE = $NAMESPACE\n"
+       exit $NOTOK
+    fi
+  fi
+}
+
+
+# Install SDN-C platform components if not already installed and start container
+
+# -----------------------
+# Main script starts here
+printf "Installing SDNC/R from startODL.sh script\n"
+ODL_HOME=${ODL_HOME:-/opt/opendaylight/current}
+ODL_FEATURES_BOOT_FILE=$ODL_HOME/etc/org.apache.karaf.features.cfg
+FEATURESBOOTMARKER="featuresBoot *="
+REPOSITORIESBOOTMARKER="featuresRepositories *="
+
+ODL_ADMIN_USERNAME=${ODL_ADMIN_USERNAME:-admin}
+ODL_REMOVEIDMDB=${ODL_REMOVEIDMDB:-true}
+
+if $ODL_REMOVEIDMDB ; then
+  if [ -f $ODL_HOME/data/idmlight.db.mv.db ]; then
+    rm $ODL_HOME/data/idmlight.db.mv.db
+  fi
+fi
+
+CCSDK_HOME=${CCSDK_HOME:-/opt/onap/ccsdk}
+SDNC_HOME=${SDNC_HOME:-/opt/onap/sdnc}
+SDNC_BIN=${SDNC_BIN:-/opt/onap/sdnc/bin}
+JDEBUG=${JDEBUG:-false}
+SDNC_AAF_ENABLED=${SDNC_AAF_ENABLED:-false}
+INSTALLED_DIR=${INSTALLED_FILE:-/opt/opendaylight/current/daexim}
+
+# Whether to intialize MYSql DB or not. Default is to initialize
+SDNC_DB_INIT=${SDNC_DB_INIT:-false}
+MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-openECOMP1.0}
+
+IS_PRIMARY_CLUSTER=${IS_PRIMARY_CLUSTER:-false}
+MY_ODL_CLUSTER=${MY_ODL_CLUSTER:-127.0.0.1}
+ENABLE_ODL_CLUSTER=${ENABLE_ODL_CLUSTER:-false}
+ENABLE_OAUTH=${ENABLE_OAUTH:-false}
+ENABLE_ODLUX_RBAC=${ENABLE_ODLUX_RBAC:-false}
+GEO_ENABLED=${GEO_ENABLED:-false}
+
+SDNRWT=${SDNRWT:-false}
+SDNRDM=${SDNRDM:-false}
+SDNRUNMDM=${SDNRUNMDM:-false}
+#SDNRODLUX_BOOTFEATURES=${SDNRODLUX_BOOTFEATURES:-sdnr-wt-helpserver-feature,sdnr-wt-odlux-core-feature,sdnr-wt-odlux-apps-feature}
+SDNROAUTH_BOOTFEATURES=${SDNROAUTH_BOOTFEATURES:-sdnr-wt-feature-aggregator-oauth}
+SDNR_NETCONF_CALLHOME_ENABLED=${SDNR_NETCONF_CALLHOME_ENABLED:-false}
+
+# Add devicemanager features
+SDNRDM_SDM_LIST=${SDNRDM_SDM_LIST:-sdnr-wt-feature-aggregator-devicemanager}
+SDNRDM_BOOTFEATURES=${SDNRDM_BOOTFEATURES:-sdnr-wt-feature-aggregator-devicemanager-base,${SDNRDM_SDM_LIST}}
+SDNRDM_UNM_BOOTFEATURES=${SDNRDM_UNM_BOOTFEATURES:-sdnr-wt-feature-aggregator-devicemanager-base,sdnr-wt-feature-aggregator-devicemanager-unm-generic}
+
+# Whether to Initialize the ElasticSearch DB.
+SDNRINIT=${SDNRINIT:-false}
+SDNRONLY=${SDNRONLY:-false}
+SDNRDBTYPE=${SDNRDBTYPE:-ELASTICSEARCH}
+SDNRDBURL=${SDNRDBURL:-http://sdnrdb:9200}
+SDNRDBCOMMAND=${SDNRDBCOMMAND:--c init -db $SDNRDBURL -dbt $SDNRDBTYPE -dbu $SDNRDBUSERNAME -dbp $SDNRDBPASSWORD $SDNRDBPARAMETER}
+
+SDNR_NORTHBOUND=${SDNR_NORTHBOUND:-false}
+SDNR_NORTHBOUND_BOOTFEATURES=${SDNR_NORTHBOUND_BOOTFEATURES:-sdnr-northbound-all}
+SDNR_NETCONF_CALLHOME_FEATURE=${SDNR_NETCONF_CALLHOME_FEATURE:-odl-netconf-callhome-ssh}
+
+# if only SDNR features then do not start A1 adapter
+if $SDNRONLY ; then
+  A1_ADAPTER_NORTHBOUND=false
+else
+  A1_ADAPTER_NORTHBOUND=${A1_ADAPTER_NORTHBOUND:-true}
+fi
+A1_ADAPTER_NORTHBOUND_BOOTFEATURES=${A1_ADAPTER_NORTHBOUND_BOOTFEATURES:-a1-adapter-northbound}
+
+NOTOK=1
+#export for installCerts.py
+export ODL_ADMIN_PASSWORD ODL_ADMIN_USERNAME
+
+if $JDEBUG ; then
+    printf "Activate remote debugging\n"
+    #JSTADTPOLICYFILE="$ODL_HOME/etc/tools.policy"
+    #echo -e "grant codebase \"file:${JAVA_HOME}/lib/tools.jar\" {\n  permission java.security.AllPermission;\n };" > $JSTADTPOLICYFILE
+    #sleep 1
+    #$JAVA_HOME/bin/jstatd -p 1089 -J-Djava.security.policy=$JSTADTPOLICYFILE &
+    EXTRA_JAVA_OPTS="${EXTRA_JAVA_OPTS} -Dcom.sun.management.jmxremote.port=1090"
+    EXTRA_JAVA_OPTS="${EXTRA_JAVA_OPTS} -Dcom.sun.management.jmxremote.rmi.port=1090"
+    EXTRA_JAVA_OPTS="${EXTRA_JAVA_OPTS} -Djava.rmi.server.hostname=$(hostname)  "
+    EXTRA_JAVA_OPTS="${EXTRA_JAVA_OPTS} -Dcom.sun.management.jmxremote.local.only=false"
+    EXTRA_JAVA_OPTS="${EXTRA_JAVA_OPTS} -Dcom.sun.management.jmxremote.ssl=false"
+    EXTRA_JAVA_OPTS="${EXTRA_JAVA_OPTS} -Dcom.sun.management.jmxremote.authenticate=false"
+    export EXTRA_JAVA_OPTS
+fi
+
+
+printf "Settings:\n"
+printf "%s\n" "  SDNC_BIN=$SDNC_BIN"
+printf "%s\n" "  SDNC_HOME=$SDNC_HOME"
+printf "%s\n" "  SDNC_DB_INIT=$SDNC_DB_INIT"
+printf "%s\n" "  ODL_CERT_DIR=$ODL_CERT_DIR"
+printf "%s\n" "  ENABLE_ODL_CLUSTER=$ENABLE_ODL_CLUSTER"
+printf "%s\n" "  ODL_REMOVEIDMDB=$ODL_REMOVEIDMDB"
+printf "%s\n" "  SDNC_REPLICAS=$SDNC_REPLICAS"
+printf "%s\n" "  ENABLE_OAUTH=$ENABLE_OAUTH"
+printf "%s\n" "  ENABLE_ODLUX_RBAC=$ENABLE_ODLUX_RBAC"
+printf "%s\n" "  SDNRWT=$SDNRWT"
+printf "%s\n" "  SDNRDM=$SDNRDM"
+printf "%s\n" "  SDNRUNMDM=$SDNRUNMDM"
+printf "%s\n" "  SDNRONLY=$SDNRONLY"
+printf "%s\n" "  SDNRINIT=$SDNRINIT"
+printf "%s\n" "  SDNRDBURL=$SDNRDBURL"
+printf "%s\n" "  SDNRDBUSERNAME=$SDNRDBUSERNAME"
+printf "%s\n" "  GEO_ENABLED=$GEO_ENABLED"
+printf "%s\n" "  IS_PRIMARY_CLUSTER=$IS_PRIMARY_CLUSTER"
+printf "%s\n" "  MY_ODL_CLUSTER=$MY_ODL_CLUSTER"
+printf "%s\n" "  PEER_ODL_CLUSTER=$PEER_ODL_CLUSTER"
+printf "%s\n" "  SDNR_NORTHBOUND=$SDNR_NORTHBOUND"
+printf "%s\n" "  AAF_ENABLED=$SDNC_AAF_ENABLED"
+printf "%s\n" "  SERVICE_NAME=$SERVICE_NAME"
+printf "%s\n" "  NAMESPACE=$NAMESPACE"
+printf "%s\n" "  SDNR_NETCONF_CALLHOME_ENABLED=$SDNR_NETCONF_CALLHOME_ENABLED"
+
+if "$SDNC_AAF_ENABLED"; then
+       export SDNC_AAF_STORE_DIR=/opt/app/osaaf/local
+       export SDNC_AAF_CONFIG_DIR=/opt/app/osaaf/local
+       export SDNC_KEYPASS=$(cat /opt/app/osaaf/local/.pass)
+       export SDNC_KEYSTORE=org.onap.sdnc.p12
+       sed -i '/cadi_prop_files/d' "$ODL_HOME"/etc/system.properties
+       echo "cadi_prop_files=$SDNC_AAF_CONFIG_DIR/org.onap.sdnc.props" >> "$ODL_HOME"/etc/system.properties
+
+       sed -i '/org.ops4j.pax.web.ssl.keystore/d' "$ODL_HOME"/etc/custom.properties
+       sed -i '/org.ops4j.pax.web.ssl.password/d' "$ODL_HOME"/etc/custom.properties
+       sed -i '/org.ops4j.pax.web.ssl.keypassword/d' "$ODL_HOME"/etc/custom.properties
+       echo "org.ops4j.pax.web.ssl.keystore=$SDNC_AAF_STORE_DIR/$SDNC_KEYSTORE" >> "$ODL_HOME"/etc/custom.properties
+       echo "org.ops4j.pax.web.ssl.password=$SDNC_KEYPASS" >> "$ODL_HOME"/etc/custom.properties
+       echo "org.ops4j.pax.web.ssl.keypassword=$SDNC_KEYPASS" >> "$ODL_HOME"/etc/custom.properties
+fi
+
+if $SDNRINIT ; then
+  #One time intialization action
+  initialize_sdnrdb
+  init_result=$?
+  printf "%s\n" "Result of init script: $init_result"
+  if $SDNRWT ; then
+    if [ $init_result -ne 0 ]; then
+      echo "db not initialized. stopping container"
+      exit $init_result
+    fi
+    printf "Proceed to initialize sdnr\n"
+  else
+    exit $init_result
+  fi
+fi
+
+# do not start container if ADMIN_PASSWORD is not set
+if [ -z "$ODL_ADMIN_PASSWORD" ]; then
+  echo "ODL_ADMIN_PASSWORD is not set"
+  exit 1
+fi
+
+# Check for MySQL DB connectivity only if SDNC_DB_INIT is set to "true"
+if $SDNC_DB_INIT; then
+#
+# Wait for database
+#
+  printf "Waiting for mysql"
+  until mysql -h dbhost -u root -p"${MYSQL_ROOT_PASSWORD}" -e "select 1" > /dev/null 2>&1
+  do
+    printf "."
+    sleep 1
+  done
+  printf "\nmysql ready"
+fi
+
+
+if [ ! -d "${INSTALLED_DIR}" ]
+then
+    mkdir -p "${INSTALLED_DIR}"
+fi
+
+if [ ! -f "${SDNC_HOME}"/.installed ]
+then
+    # for integration testing. In OOM, a separate job takes care of installing it.
+    if $SDNC_DB_INIT; then
+      printf "Installing SDN-C database\n"
+      "${SDNC_HOME}"/bin/installSdncDb.sh
+    fi
+    printf "Installing SDN-C keyStore\n"
+    "${SDNC_HOME}"/bin/addSdncKeyStore.sh
+    printf "Installing A1-adapter trustStore\n"
+    "${SDNC_HOME}"/bin/addA1TrustStore.sh
+
+    if [ -x "${SDNC_HOME}"/svclogic/bin/install.sh ]
+    then
+      printf "Installing directed graphs\n"
+      "${SDNC_HOME}"/svclogic/bin/install.sh
+    fi
+
+  if $SDNRWT ; then install_sdnrwt_features ; fi
+  
+  if $ENABLE_OAUTH ; then
+    cp $SDNC_HOME/data/oauth-aaa-app-config.xml $(find $ODL_HOME/system/org/opendaylight/aaa/ -name *aaa-app-config.xml)
+    echo -e "\norg.ops4j.pax.web.session.cookie.comment = disable" >> $ODL_HOME/etc/org.ops4j.pax.web.cfg
+    install_sdnr_oauth_features
+  fi
+
+  # The enable_odl_cluster call should not be moved above this line as the cleanFeatureBoot will overwrite entries. Ex: odl-jolokia
+  if $ENABLE_ODL_CLUSTER ; then enable_odl_cluster ; fi
+
+  if $SDNR_NORTHBOUND ; then install_sdnr_northbound_features ; fi
+  if $A1_ADAPTER_NORTHBOUND ; then install_a1_northbound_features ; fi
+
+  printf "%s" "Installed at $(date)" > "${SDNC_HOME}"/.installed
+fi
+
+#cp /opt/opendaylight/current/certs/* /tmp
+#cp /var/custom-certs/* /tmp
+
+if [ -n "$OVERRIDE_FEATURES_BOOT" ] ; then
+  printf "%s\n" "Override features boot: $OVERRIDE_FEATURES_BOOT"
+  sed -i "/$FEATURESBOOTMARKER/c\featuresBoot = $OVERRIDE_FEATURES_BOOT" "$ODL_FEATURES_BOOT_FILE"
+fi
+
+# Odl configuration done
+ODL_REPOSITORIES_BOOT=$(sed -n "/$REPOSITORIESBOOTMARKER/p" "$ODL_FEATURES_BOOT_FILE")
+ODL_FEATURES_BOOT=$(sed -n "/$FEATURESBOOTMARKER/p" "$ODL_FEATURES_BOOT_FILE")
+export ODL_FEATURES_BOOT
+
+# Create ODL data log directory (it nornally is created after karaf
+# is started, but needs to exist before installCerts.py runs)
+if [ -z "$ODL_CERT_DIR" ] ; then
+  printf "No certs provided. Skip installation.\n"
+else
+  printf "Start background cert installer\n"
+  mkdir -p /opt/opendaylight/data/log
+  nohup python3 "${SDNC_BIN}"/installCerts.py &
+  printf "Start monitoring certificate installation. \n"
+  nohup sh "${SDNC_BIN}"/monitorCertsInstall.sh &
+fi
+
+printf "Startup opendaylight\n"
+printf "%s\n" "$ODL_REPOSITORIES_BOOT"
+printf "%s\n" "$ODL_FEATURES_BOOT"
+
+exec "${ODL_HOME}"/bin/karaf server