From: Claudio David Gasparini Date: Fri, 21 May 2021 05:41:33 +0000 (+0000) Subject: Merge "Initial doc structure" X-Git-Tag: 1.0.0~15 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=478bd59ad277738b9788b73230168bdd183bcba7;hp=811e44e99a8884b2c316ea4a88ef88e75ee0e47d;p=oam%2Fnf-oam-adopter.git Merge "Initial doc structure" --- diff --git a/solution/docker-compose.yaml b/solution/docker-compose.yaml index 595f1f8..1490d22 100644 --- a/solution/docker-compose.yaml +++ b/solution/docker-compose.yaml @@ -1,42 +1,44 @@ version: "3.5" services: -# ves-collector: -# restart: unless-stopped -# ports: -# - "8080:8080/udp" -# image: nexus3.onap.org:10001/onap/org.onap.dcaegen2.collectors.ves.vescollector:latest -# container_name: vescollector -# environment: -# DMAAPHOST: 50.50.50.50 + vescollector: + restart: unless-stopped + ports: + - "8080:8080/udp" + network_mode: host + image: nexus3.onap.org:10001/onap/org.onap.dcaegen2.collectors.ves.vescollector:latest + container_name: vescollector + environment: + DMAAPHOST: 50.50.50.50 ves-nf-oam-adopter-ran-mock: ports: - - "444:443/tcp" + - "443:443/tcp" network_mode: host restart: unless-stopped - image: nexus3.o-ran-sc.org:10003/o-ran-sc/ves-nf-oam-adopter-ran-mock:latest + image: nexus3.o-ran-sc.org:10004/o-ran-sc/ves-nf-oam-adopter-ran-mock:latest container_name: ves-nf-oam-adopter-ran-mock environment: KEY_PASSWORD: nf-oam-adopter KEY_STORE_PASSWORD: nf-oam-adopter SNMP-DESTINY: 0.0.0.0/162 + SERVER_PORT: 443 ves-nf-oam-adopter: ports: - - "162:162/udp" - - "443:443/tcp" + - "443:444/tcp" network_mode: host restart: unless-stopped - image: nexus3.o-ran-sc.org:10003/o-ran-sc/ves-nf-oam-adopter:latest + image: nexus3.o-ran-sc.org:10004/o-ran-sc/ves-nf-oam-adopter:latest container_name: ves-nf-oam-adopter environment: + SERVER_PORT: 444 USERNAME: admin PASSWORD: admin KEY_PASSWORD: nf-oam-adopter KEY_STORE_PASSWORD: nf-oam-adopter TRUST_STORE_PASSWORD: nf-oam-adopter - VES_COLLECTOR: http://vescollector:8080/eventListener/v7 + VES_COLLECTOR: http://0.0.0.0:8080/eventListener/v7 VES_ENCODED_AUTH: YWRtaW46YWRtaW4= - PM_SYNC_TIME_START: "06:05:00" - PM_SYNC_TIME_FREQ: "24:00:00" \ No newline at end of file + PM_SYNC_TIME_START: "14:25:00" + PM_SYNC_TIME_FREQ: 30 \ No newline at end of file diff --git a/ves-nf-oam-adopter/pom.xml b/ves-nf-oam-adopter/pom.xml index aa53ec3..890d575 100644 --- a/ves-nf-oam-adopter/pom.xml +++ b/ves-nf-oam-adopter/pom.xml @@ -50,5 +50,8 @@ ves-nf-oam-adopter-api ves-nf-oam-adopter-event-notifier ves-nf-oam-adopter-snmp-manager + ves-nf-oam-adopter-pm-manager + ves-nf-oam-adopter-pm-sb-rest-client + ves-nf-oam-adopter-app \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/application.yml b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/application.yml new file mode 100644 index 0000000..fee8a56 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/application.yml @@ -0,0 +1,34 @@ +spring.devtools.restart.log-condition-evaluation-delta: false +logging.config: log4j2.yml +server: + port : ${SERVER_PORT:443} + username: ${USERNAME:admin} + password: ${PASSWORD:admin} + ssl: + enabled: true + key-store-type: JKS + key-alias: nf-oam-adopter + key-store: ${KEYSTORE_PATH:ssl/nf-oam-adopter-keystore.jks} + key-store-password: ${KEY_STORE_PASSWORD:nf-oam-adopter} + key-password: ${KEY_PASSWORD:nf-oam-adopter} + trust-store: ${TRUST_STORE_PATH:ssl/nf-oam-adopter-truststore.jks} + trust-store-password: ${TRUST_STORE_PASSWORD:nf-oam-adopter} + enabled-protocols: TLSv1.3 + ciphers: TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_CCM_8_SHA256, TLS_AES_128_CCM_SHA256 +ves-collector: + url: ${VES_COLLECTOR} + vesEncodedAuth: ${VES_ENCODED_AUTH} +http-client: + conection-timeout: ${CONNECTION_TIMEOUT:600} + response-timeout: ${RESPONSE_TIMEOUT:600} +pm-rest-manager: + synchronization-time-start: ${PM_SYNC_TIME_START} + synchronization-time-frequency: ${PM_SYNC_TIME_FREQ} + mapping-config-path: ${PM_MAPPING_FILE_PATH:mapping-configuration/pm-ves-message-mapping.yaml} + ran-token-endpoint: /auth/token + ran-pm-endpoint: /pm/files + ran-time-zone-offset-endpoint: /system/timeZone +snmp-manager: + host: "0.0.0.0" + port: ${SNMP_PORT:162} + mapping-config-path: ${FM_MAPPING_FILE_PATH:mapping-configuration/fm-ves-message-mapping.yaml} \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/fm-ves-message-mapping.yaml b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/fm-ves-message-mapping.yaml new file mode 100644 index 0000000..24fd5d7 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/fm-ves-message-mapping.yaml @@ -0,0 +1,21 @@ +reporting-entity-name: "NF-OAM-ADOPTER" +reporting-entity-id: "NF-OAM-ADOPTER" +nf-vendor-name: "SOME-VENDOR" +traps: + - oid: "default" + name: "SNMP_Fault" + event-severity: "CRITICAL" + event-source-type: "Unknown" + - oid: "1.3.6.1.4.1.1007.0.0.1.0.1" + name: "PortDOWN" + event-severity: "MAJOR" + oid-event-id: "1.3.6.1.4.1.1007.2.6.9.0" + oid-event-sequence: "0" + oid-reporting-entity-id: "1.3.6.1.4.1.1007.0.0.1.0.6" + oid-source-name: "1.3.6.1.4.1.1007.0.0.1.0.2" + oid-specific-problem-desc: "1.3.6.1.4.1.1007.0.0.1.0.3" + oid-alarm-interface-name: "1.3.6.1.4.1.1007.0.0.1.0.7" + oid-start-epoch-microsec: "1.3.6.1.4.1.1007.0.0.1.0.4" + oid-last-epoch-microsec: "1.3.6.1.4.1.1007.0.0.1.0.5" + event-category: "link" + event-source-type: "port" \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/log4j2.yml b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/log4j2.yml new file mode 100644 index 0000000..c10a74b --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/log4j2.yml @@ -0,0 +1,48 @@ +Configuration: + status: debug + + appenders: + Console: + name: LogToConsole + PatternLayout: + Pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" + + RollingFile: + - name: LogToRollingFile + fileName: logs/o-ran-ves-adapter.log + filePattern: "logs/$${date:yyyy-MM}/o-ran-ves-adapter-%d{MM-dd-yyyy}-%i.log.gz" + PatternLayout: + pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n" + Policies: + SizeBasedTriggeringPolicy: + size: 100MB + DefaultRollOverStrategy: + max: 10 + + Loggers: + logger: + - name: org.o.ran.oam.nf.oam + level: debug + additivity: false + AppenderRef: + - ref: LogToConsole + - ref: LogToRollingFile + - name: org.springframework.boot.actuate.audit.listener + level: info + additivity: false + AppenderRef: + - ref: LogToConsole + - ref: LogToRollingFile + - name: org.springframework + level: warn + additivity: false + AppenderRef: + - ref: LogToConsole + - ref: LogToRollingFile + + Root: + level: info + AppenderRef: + AppenderRef: + - ref: LogToConsole + - ref: LogToRollingFile diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/pm-ves-message-mapping.yaml b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/pm-ves-message-mapping.yaml new file mode 100644 index 0000000..073e3c7 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/pm-ves-message-mapping.yaml @@ -0,0 +1,26 @@ +reporting-entity-name: "NF-OAM-ADOPTER" +reporting-entity-id: "ONAP-NF-OAM-SOME-VENDOR-ADAPTER" +nf-vendor-name: "SOME-VENDOR" +event-source-type: "SNMP Agent" +event-name: "PM_Notification" +measurement-interval: 40 +priority: "High" +batch-size: 200 +csv: + source-name: Name + event-id: + - PortId + - Date + - Time + additional-fields: + - PortId + - Name + - Date + - Time + additional-measurements-name: "Port measurements" + additional-measurements: + - A_Parameter + - B_Parameter + - C_Parameter + - D_Parameter + - E_Parameter \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-cert.pem b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-cert.pem new file mode 100644 index 0000000..6f3a7ac --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDizCCAnOgAwIBAgIUUR7hr58NdGQKpF3gmqUJRSdYwZgwDQYJKoZIhvcNAQEL +BQAwVTELMAkGA1UEBhMCU0sxEzARBgNVBAgMCkJyYXRpc2xhdmExEzARBgNVBAcM +CkJyYXRpc2xhdmExDTALBgNVBAoMBEFUJlQxDTALBgNVBAsMBEFUJlQwHhcNMjEw +NTA0MDgxNjUzWhcNMzEwNTAyMDgxNjUzWjBVMQswCQYDVQQGEwJTSzETMBEGA1UE +CAwKQnJhdGlzbGF2YTETMBEGA1UEBwwKQnJhdGlzbGF2YTENMAsGA1UECgwEQVQm +VDENMAsGA1UECwwEQVQmVDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANgJZ0Vz0Aa0tFWAzJqeaVeT52zLweSWv2rbXFka/2ClAioUUSm7j0+y7lT9yTbK +J27opYojlB0wPRBor5n587lpTP9yJYephIQvUdfsgP62xXANVcd1MVWRbI0ldxtc +EOWaW/w2b3yDLa+o+zsG0KN7IAYmDfb7ZVc5fn+zU9oqO+UlhVbgPhJjRdlGJjoL +zCZYP8ip6xEmRDDZZ+KTazevYZ4ZFe4VWVbOn3eRTBWVea3HAirmbNSEWG1HWZ0y +BjGy+eI9HbHVLpuLObPUASpZCvEjwS2/IYwYkpBREwSmLUXu6qj8rp0F3GVTk8D0 +Y6xy6CtmcDFz2KOYWD9KKm8CAwEAAaNTMFEwHQYDVR0OBBYEFBALTA7uLbxLThTx +a/R/0hcydIsjMB8GA1UdIwQYMBaAFBALTA7uLbxLThTxa/R/0hcydIsjMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAD0czkrPMahhFNiJD5fmW3T +o3QMCS/WQ4iCZ3/ROQ6P8zbNqbkZxy+yF6b1kii81wDd5jnoo1b/zhjHoUb7pUWg +NFZXqF+zajKr0zXcDGbuksIlukVmB6Vz83jEowGxb5xakh9gluxukabkhO7yBUFY +sc4B34n1keOKKQKdmgxG7FBS77n0Em+9NeuLzvP0S9AvkQdgDgXRX2yVjy8gVGEA +Iz+IEIDE/oQQ3HaUQTIItnMNhg1orUzOzps5FdOtFEtd7XwjqSgu+NR77G6KOFcR +RFw9V3uEd2XUn+sHUu81yfseBjMcneuvKBr/KIbwlj86kEAyaTedL2oRX6Ful6Q= +-----END CERTIFICATE----- diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-key.pem b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-key.pem new file mode 100644 index 0000000..011107e --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIbmqjaTYftFoCAggA +MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECIAcQM6jVuDQBIIEyOixt6jiuuRv +6IYnMnmYvaeWIxoMpqvMHSoWFSvSdyCuGdTJv+qxit+HpVOGqhVRckSv0nAAbEdE +jw0PVyAgfWX7vQca1YK2mxw5tGrNsSyQ5LPtS5QICe4fDew8VwiGXWdQhnxvIxUW +xORfAOTar2qEgE0OBsYVBEjdU3mS3RFRKDtCVXYxiII6/24Nsf7bmz438VxShwog +A5Zq6sQtqOjF3sKfRgkimOGLgBw7DACI852bEVffySdt8CdGZuAAfD6PucmQSTHp +CSdmCELBA4p6juNFgpRqvm5qlG/7ZBJhcjGU7CAN1v8oYBH0TB44ek4hOFzT9b5P +8icBXmg4w2ysWz6OPbwcQj8pG1yRb7WDUulntlSUijI2AXFV2SWIHZ2APFdVQ1c4 +qrivre66FIfo79/I+RTo5MMp2wmJbAjsSaO4571hwY9Cap0TdeJ+KmIKpK+HYwLQ +iwJip2TtBUmd/ANPnJmgrG2pAeiahciJ0gMGwN2L5uxoiV+FSLwEQ7JCXZn2ET9B +ai2ZodjIHjZTAT/dtX9gS/yJyHC20HpA3mVtjkenGHaBbs0ji2u1bK9JUgNb43R1 +I7r4BfsYav3+FTq1xoU/vFlP7vxX9cgUduda4rTu7ZNu56RgxKFeqsWl5gbUIX6y +UU2W1R3TXVpoBPHzpEo2Vcig6exEEVEaO8HXu16UD1+wvwLYkSlwWjKby1pVOdNw ++ZnZv5aLIFk2UC1yJ7AJcxHLIcmJD6jBlzpGmQOqNvVb4Qig0NyMkz0bZAJ5SI/t +6mZZXHDmgRLfjluawVYIoIVcflm/yfRh6nELUAfh/IAIVyDvaEtEwfK3SlWXrvP4 +j+F8EacnQm7O1rFgR+p2AxMtAdAm7E4JVoNpHSWbv36EI34RaoVPng7ueBSkG3Uk +7qrbb/lWjXveKfizkkuUUFZWKiSyXAxYiXu9sQjBlN2EWSgBAix7WpqSh2CPROO4 +gn51n7TKyer5CcUqwzMz5SLhRSNkoBY82vIyBZyf7UrRztmJPrvbr4UQSoiqLrey +DPaT0LHtyJZWuNZS2ki+WI1nnKkFtWgl7Yv57EtBwHqTpARvH4NiF8ryJbp8rl6R +WMz5haeuBmFz/IXZtOsRXVR+kjhShBKygKYRtUGEc3sSDL2HsA47pCCaFW8907NP +dfv1WeKyI6d0snBIMKypzFGo17CtdcxsNiAgcrwW2cvwsDyysimZQPa7dr1uAwEX +WU2WAaoGmxShZB9fvdIeg4bydnJAlVOjotWs+kwPzCLFk++DSQ4HiElJnwawuPfB +XWqk7ZaKZEiZXNJMyMGIqKo8w+88uIQTd4YNbfhBgvSlgf8Y5EaYbzx68yUkPeOR +Urli4hXpSkkB3DtmRMquUg1xPn6Ao+vvEoXwiUPg61YQIO1RvTr2vVAWVj1WYcJI +4k6sAi6HhhlGEVL1bxFMpkX9h/Jwd0YgDYAUFJ2DPnZ+18gbdpA7QZp/SBKwZpTh +cbNXBkwv2Wa4u/yQsoqoyrxOTzpfiRYVvr4Xmi40TuLC4JEYqTdg+HE5ovjfIFTz +dxOMEon6JwvwXxWdqZS655hVcG0pH1JvBVouGrWB5EOElVCzDcvquacDofaemcA9 +lkve4yZbTmJRwZrUBCmTOQ== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-keystore.jks b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-keystore.jks new file mode 100644 index 0000000..8712bd5 Binary files /dev/null and b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-keystore.jks differ diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-truststore.jks b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-truststore.jks new file mode 100644 index 0000000..42cfc88 Binary files /dev/null and b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter-truststore.jks differ diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter.p12 b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter.p12 new file mode 100644 index 0000000..8b54595 Binary files /dev/null and b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/configuration/ssl/nf-oam-adopter.p12 differ diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/docs/api/swagger/openapi.yaml b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/docs/api/swagger/openapi.yaml new file mode 100644 index 0000000..6a02e63 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/docs/api/swagger/openapi.yaml @@ -0,0 +1,124 @@ +# ============LICENSE_START======================================================= +# Copyright © 2021 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. +# +# SPDX-License-Identifier: Apache-2.0 +# ============LICENSE_END========================================================= +openapi: 3.0.3 +info: + title: O-RAN OAM Adopter PM Manager + description: API for O-RAN OAM Adopter PM Manager service. + version: "1.0.0" + license: + name: "Apache 2.0" + url: "http://www.apache.org/licenses/LICENSE-2.0" + +servers: + - url: https://example.io/v1 + +security: + - BasicAuth: [] + +paths: + /: + get: + tags: + - controller + summary: Read all adapters host address + description: Returns a list of adapters host address + operationId: getAllAdapters + responses: + '200': + description: Successfully returned a list of adapters host address + content: + application/json: + schema: + type: array + items: + type: string + '400': + $ref: '#/components/responses/400Error' + + + /adapter/{host}: + delete: + tags: + - controller + description: Delete an adapter by host address + operationId: removeAdapter + parameters: + - name: host + in: path + required: true + schema: + type: string + + responses: + '200': + description: Successfully deleted an adapter + '400': + description: Invalid request + '401': + description: Unauthorized + '404': + description: adapter not found + + /adapter: + post: + tags: + - controller + description: create an adapter instance + operationId: addAdapter + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Adapter' + responses: + '200': + description: Successfully returned a list of adapters + '400': + $ref: '#/components/responses/400Error' + +components: + schemas: + Adapter: + type: object + properties: + host: + type: string + mechId: + type: object + properties: + username: + type: string + password: + type: string + required: + - username + - password + required: + - host + - mechId + + responses: + 400Error: + description: Invalid request + content: + application/json: + schema: + type: object + properties: + message: + type: string \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/pom.xml b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/pom.xml new file mode 100644 index 0000000..c92c564 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/pom.xml @@ -0,0 +1,239 @@ + + + + 4.0.0 + + + org.o-ran-sc.oam + ves-nf-oam-adopter-parent + 1.0.0-SNAPSHOT + ../ves-nf-oam-adopter-parent/pom.xml + + + ves-nf-oam-adopter-app + + + + ves-nf-oam-adopter + + + + + ${project.groupId} + ves-nf-oam-adopter-api + + + ${project.groupId} + ves-nf-oam-adopter-event-notifier + + + ${project.groupId} + ves-nf-oam-adopter-snmp-manager + + + ${project.groupId} + ves-nf-oam-adopter-pm-manager + + + ${project.groupId} + ves-nf-oam-adopter-pm-sb-rest-client + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.apache.httpcomponents.client5 + httpclient5 + + + io.swagger.core.v3 + swagger-annotations + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + io.swagger.codegen.v3 + swagger-codegen-maven-plugin + + + + generate + + + ${project.basedir}/docs/api/swagger/openapi.yaml + org.o.ran.oam.nf.oam.adopter.app.controller + org.o.ran.oam.nf.oam.adopter.model + org.o.ran.oam.nf.oam.adopter.api + spring + false + + src/gen/java + java11 + true + true + true + + + + + + + + + + + docker + + false + + + + + io.fabric8 + docker-maven-plugin + 0.34.1 + true + + true + + + ${nexus.repository}${image.name} + + ${nexus.repository.mirror}${base.image} + + ${project.version} + + ${image.workdir} + + + java + -jar + ${project.artifactId}-${project.version}.jar + + + + ${image.workdir} + + + + true + + ${project.groupId}:${project.artifactId} + + ${project.build.finalName}.jar + + + + + ${base.config}application.yml + . + application.yml + + + ${base.config}fm-ves-message-mapping.yaml + ./mapping-configuration + fm-ves-message-mapping.yaml + + + ${base.config}pm-ves-message-mapping.yaml + ./mapping-configuration + pm-ves-message-mapping.yaml + + + ${base.config}log4j2.yml + + + ${base.config}/ssl/nf-oam-adopter-keystore.jks + ./ssl + nf-oam-adopter-keystore.jks + + + ${base.config}/ssl/nf-oam-adopter-truststore.jks + ./ssl + nf-oam-adopter-truststore.jks + + + + + + + + + + + build-docker-image + package + + build + + + + push-image + deploy + + push + + + + + + + + + + \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/AdapterApplication.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/AdapterApplication.java new file mode 100644 index 0000000..59ce697 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/AdapterApplication.java @@ -0,0 +1,31 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = {"org.o.ran.oam.nf.oam.adopter"}) +public class AdapterApplication { + + public static void main(final String[] args) { + SpringApplication.run(AdapterApplication.class, args); + } +} \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/HttpAsyncClientConfig.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/HttpAsyncClientConfig.java new file mode 100644 index 0000000..5404ca6 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/HttpAsyncClientConfig.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.config; + +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.o.ran.oam.nf.oam.adopter.app.http.HttpCientFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class HttpAsyncClientConfig { + + @Value("${server.ssl.trust-store:#{null}}") + private String trustStore; + @Value("${server.ssl.trust-store-password:#{null}}") + private String trustStorePassword; + @Value("${http-client.conection-timeout:600}") + private Long conectionTimeout; + @Value("${http-client.response-timeout:600}") + private Long responseTimeout; + + @Bean(initMethod = "start", destroyMethod = "close") + public CloseableHttpAsyncClient getHttpClient() + throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException { + return HttpCientFactory.createClient(trustStore, trustStorePassword, conectionTimeout, responseTimeout); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/LoginAttemptsLogger.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/LoginAttemptsLogger.java new file mode 100644 index 0000000..072fbb9 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/LoginAttemptsLogger.java @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository; +import org.springframework.boot.actuate.audit.listener.AuditApplicationEvent; +import org.springframework.context.annotation.Bean; +import org.springframework.context.event.EventListener; +import org.springframework.security.web.authentication.WebAuthenticationDetails; +import org.springframework.stereotype.Component; + +@Component +public class LoginAttemptsLogger { + private static final Logger LOG = LoggerFactory.getLogger(LoginAttemptsLogger.class); + + /** + * audit Application Event. + */ + @EventListener + public void auditEventHappened(final AuditApplicationEvent auditApplicationEvent) { + final AuditEvent auditEvent = auditApplicationEvent.getAuditEvent(); + final WebAuthenticationDetails details = (WebAuthenticationDetails) auditEvent.getData().get("details"); + if (details == null) { + LOG.info("AUDIT: User: {} Event Type: {}", auditEvent.getPrincipal(), auditEvent.getType()); + return; + } + LOG.info("AUDIT: User: {} Event Type: {} Remote IP address: {}", + auditEvent.getPrincipal(), auditEvent.getType(), details.getRemoteAddress()); + } + + @Bean + public InMemoryAuditEventRepository auditEventRepository() throws Exception { + return new InMemoryAuditEventRepository(); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/SecurityConfiguration.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/SecurityConfiguration.java new file mode 100644 index 0000000..2fc030f --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/config/SecurityConfiguration.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.config; + +import org.o.ran.oam.nf.oam.adopter.app.properties.ServerProperties; +import org.o.ran.oam.nf.oam.adopter.app.properties.SslProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@EnableConfigurationProperties +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + private static final String ADMIN_ROLE = "ADMIN"; + private final ServerProperties properties; + + @Autowired + public SecurityConfiguration(final ServerProperties properties) { + this.properties = properties; + } + + @Override + protected void configure(final HttpSecurity http) throws Exception { + final SslProperties ssl = properties.getSsl(); + if (ssl != null && ssl.getEnabled() != null && ssl.getEnabled()) { + http.requiresChannel().anyRequest().requiresSecure(); + } + http.csrf().disable() + .antMatcher("/adapters/**") + .authorizeRequests().anyRequest() + .hasRole(ADMIN_ROLE).and() + .httpBasic(); + } + + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication().withUser(properties.getUsername()).password("{noop}" + properties.getPassword()) + .roles(ADMIN_ROLE); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/AdapterController.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/AdapterController.java new file mode 100644 index 0000000..a6fb63d --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/AdapterController.java @@ -0,0 +1,72 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.controller; + +import java.util.List; +import lombok.SneakyThrows; +import org.o.ran.oam.nf.oam.adopter.api.ControllerApi; +import org.o.ran.oam.nf.oam.adopter.model.Adapter; +import org.o.ran.oam.nf.oam.adopter.model.AdapterMechId; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.PerformanceManagementAdaptersDeployer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@SpringBootApplication(scanBasePackages = {"org.o.ran.oam.adopter"}) +@RequestMapping(path = "/adapters") +public class AdapterController implements ControllerApi { + + private static final Logger LOG = LoggerFactory.getLogger(AdapterController.class); + + private final PerformanceManagementAdaptersDeployer deployer; + + @Autowired + public AdapterController(final PerformanceManagementAdaptersDeployer deployer) { + this.deployer = deployer; + } + + @Override + @SneakyThrows + public ResponseEntity addAdapter(final Adapter adapter) { + LOG.info("Request triggered: addAdapter"); + final AdapterMechId mechIdDto = adapter.getMechId(); + deployer.create(adapter.getHost(), mechIdDto.getUsername(), mechIdDto.getPassword()); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity> getAllAdapters() { + LOG.info("Request triggered: getAllAdapters"); + return ResponseEntity.ok(deployer.getAll()); + } + + @Override + @SneakyThrows + public ResponseEntity removeAdapter(final String host) { + LOG.info("Request triggered: removeAdapter"); + deployer.delete(host); + return ResponseEntity.ok().build(); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/RestExceptionHandler.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/RestExceptionHandler.java new file mode 100644 index 0000000..a4a7d6f --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/RestExceptionHandler.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.controller; + +import java.util.HashMap; +import java.util.Map; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.AlreadyPresentException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.NotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class RestExceptionHandler { + private static final Logger LOG = LoggerFactory.getLogger(RestExceptionHandler.class); + + /** + * Handle Already Present Exceptions. + */ + @ExceptionHandler({AlreadyPresentException.class}) + public static ResponseEntity handleBadRequestExceptions(final AlreadyPresentException exception) { + LOG.error("Request failed", exception); + return ResponseEntity + .badRequest() + .body(exception.getMessage()); + } + + /** + * Handle Not Found Exceptions. + */ + @ExceptionHandler({NotFoundException.class}) + public static ResponseEntity handleNotFoundExceptions(final NotFoundException exception) { + LOG.error("Request failed", exception); + return ResponseEntity.notFound().build(); + } + + /** + * Handle MethodArgument Not Valid Exceptions. + */ + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + public Map handleValidationExceptions(final MethodArgumentNotValidException ex) { + final Map errors = new HashMap<>(); + ex.getBindingResult().getAllErrors().forEach((error) -> { + final String fieldName = ((FieldError) error).getField(); + final String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + return errors; + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/TimeZoneServiceProvider.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/TimeZoneServiceProvider.java new file mode 100644 index 0000000..c201ce6 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/controller/TimeZoneServiceProvider.java @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.controller; + +import java.time.ZoneId; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.PerformanceManagementAdaptersDeployer; +import org.o.ran.oam.nf.oam.adopter.snmp.manager.api.TimeZoneOffsetService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class TimeZoneServiceProvider implements TimeZoneOffsetService { + + private final PerformanceManagementAdaptersDeployer deployer; + + @Autowired + public TimeZoneServiceProvider(final PerformanceManagementAdaptersDeployer deployer) { + this.deployer = deployer; + } + + @Override + public ZoneId getTimeZone(final String host) { + return deployer.getTimeZone(host); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/http/HttpCientFactory.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/http/HttpCientFactory.java new file mode 100644 index 0000000..7184c28 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/http/HttpCientFactory.java @@ -0,0 +1,93 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.http; + +import java.io.File; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import javax.net.ssl.SSLContext; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.cookie.StandardCookieSpec; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.core5.http2.HttpVersionPolicy; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.util.Timeout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class HttpCientFactory { + private static final Logger LOG = LoggerFactory.getLogger(HttpCientFactory.class); + + /** + * Generates a CloseableHttpAsyncClient. + */ + public static CloseableHttpAsyncClient createClient(final String trustStore, + final String trustStorePassword, final Long conectionTimeout, final Long responseTimeout) + throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException, + CertificateException { + final SSLContext sslContext = getSslContext(new File(trustStore), trustStorePassword); + return trustTrustStore(sslContext, conectionTimeout, responseTimeout); + } + + private static SSLContext getSslContext(final File trustStoreFilePath, final String trustStorePassword) + throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException { + return new SSLContextBuilder() + .loadTrustMaterial(trustStoreFilePath.toURI().toURL(), trustStorePassword.toCharArray()) + .build(); + } + + private static CloseableHttpAsyncClient trustTrustStore(final SSLContext sslContext, + final Long conectionTimeout, final Long responseTimeout) { + LOG.info("Trust all certificates under truststore"); + final PoolingAsyncClientConnectionManager connectionManager = + PoolingAsyncClientConnectionManagerBuilder.create().setTlsStrategy( + ClientTlsStrategyBuilder.create() + .setSslContext(sslContext) + .setHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build()) + .build(); + + return HttpAsyncClients.custom() + .setConnectionManager(connectionManager) + .setDefaultRequestConfig(createDefaultRequestConfig(conectionTimeout, responseTimeout)) + .setVersionPolicy(HttpVersionPolicy.NEGOTIATE) + .build(); + } + + private static RequestConfig createDefaultRequestConfig(final Long conectionTimeout, final Long responseTimeout) { + return RequestConfig.custom() + .setConnectTimeout(Timeout.ofSeconds(conectionTimeout)) + .setResponseTimeout(Timeout.ofSeconds(responseTimeout)) + .setCookieSpec(StandardCookieSpec.STRICT) + .build(); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/properties/ServerProperties.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/properties/ServerProperties.java new file mode 100644 index 0000000..1096cfb --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/properties/ServerProperties.java @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.properties; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "server") +@Data +@NoArgsConstructor +public class ServerProperties { + private int port; + private String username; + private String password; + private SslProperties ssl; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/properties/SslProperties.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/properties/SslProperties.java new file mode 100644 index 0000000..6e34bc9 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/main/java/org/o/ran/oam/nf/oam/adopter/app/properties/SslProperties.java @@ -0,0 +1,29 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app.properties; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class SslProperties { + private Boolean enabled; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/test/java/org/o/ran/oam/nf/oam/adopter/app/AdapterApplicationTest.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/test/java/org/o/ran/oam/nf/oam/adopter/app/AdapterApplicationTest.java new file mode 100644 index 0000000..3b9cdf3 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/test/java/org/o/ran/oam/nf/oam/adopter/app/AdapterApplicationTest.java @@ -0,0 +1,164 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.app; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.google.gson.Gson; +import java.time.ZoneId; +import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.o.ran.oam.nf.oam.adopter.app.controller.TimeZoneServiceProvider; +import org.o.ran.oam.nf.oam.adopter.model.Adapter; +import org.o.ran.oam.nf.oam.adopter.model.AdapterMechId; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.PerformanceManagementMapperConfigProvider; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.PerformanceManagementAdaptersDeployer; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.AlreadyPresentException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.NotFoundException; +import org.o.ran.oam.nf.oam.adopter.snmp.manager.SnmpMappingConfigurationProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +class AdapterApplicationTest { + + private static final Gson GSON = new Gson(); + + @Autowired + private MockMvc mockMvc; + @Autowired + private TimeZoneServiceProvider timeZoneServiceProvider; + @MockBean + private PerformanceManagementAdaptersDeployer deployer; + @MockBean + private SnmpMappingConfigurationProvider snmpProvider; + @MockBean + private PerformanceManagementMapperConfigProvider pmProvider; + @Autowired + private WebApplicationContext context; + + + @BeforeEach + public void applySecurity() { + mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build(); + } + + @Test + @WithMockUser(username = "admin", roles = "ADMIN") + public void testGetAllAdapters() throws Exception { + when(deployer.getAll()).thenReturn(Collections.singletonList("mockResult")); + + mockMvc.perform(get("/adapters/").secure(true).contentType(MediaType.APPLICATION_JSON)).andDo(print()) + .andExpect(status().isOk()).andExpect(content().string(containsString("mockResult"))); + } + + @Test + @WithMockUser(username = "admin", roles = "ADMIN") + public void testDeleteAdapter() throws Exception { + mockMvc.perform(delete("/adapters/adapter/172.10.55.3").secure(true).contentType(MediaType.APPLICATION_JSON)) + .andDo(print()).andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "admin", roles = "ADMIN") + public void testNotFound() throws Exception { + doThrow(NotFoundException.class).when(deployer).delete(anyString()); + + mockMvc.perform(delete("/adapters/adapter/172.10.55.3").secure(true).contentType(MediaType.APPLICATION_JSON)) + .andDo(print()).andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "admin", roles = "ADMIN") + public void testAddAdapter() throws Exception { + + final Adapter adapter = new Adapter(); + adapter.setHost("172.10.55.3"); + + final AdapterMechId mechId = new AdapterMechId(); + mechId.username("admin"); + mechId.password("somePass"); + adapter.setMechId(mechId); + + mockMvc.perform(post("/adapters/adapter").secure(true).contentType(MediaType.APPLICATION_JSON) + .content(GSON.toJson(adapter))).andDo(print()).andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "admin", roles = "ADMIN") + public void testAlreadyExist() throws Exception { + + final Adapter adapter = new Adapter(); + adapter.setHost("172.10.55.3"); + + final AdapterMechId mechId = new AdapterMechId(); + mechId.username("admin"); + mechId.password("somePass"); + adapter.setMechId(mechId); + + doThrow(AlreadyPresentException.class).when(deployer).create(anyString(), anyString(), anyString()); + + mockMvc.perform(post("/adapters/adapter").secure(true).contentType(MediaType.APPLICATION_JSON) + .content(GSON.toJson(adapter))).andDo(print()).andExpect(status().isBadRequest()); + } + + @Test + @WithMockUser(username = "admin", roles = "ADMIN") + public void testMissingArguments() throws Exception { + + final Adapter adapter = new Adapter(); + adapter.setHost("172.10.55.3"); + + final AdapterMechId mechId = new AdapterMechId(); + mechId.username("admin"); + adapter.setMechId(mechId); + + + mockMvc.perform(post("/adapters/adapter").secure(true).contentType(MediaType.APPLICATION_JSON) + .content(GSON.toJson(adapter))).andDo(print()).andExpect(status().isBadRequest()); + } + + @Test + public void test() { + final ZoneId zoneId = ZoneId.of("+02:00"); + when(deployer.getTimeZone("172.10.55.3")).thenReturn(zoneId); + assertEquals(zoneId, timeZoneServiceProvider.getTimeZone("172.10.55.3")); + } +} \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/test/resources/application.yml b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/test/resources/application.yml new file mode 100644 index 0000000..27b27ff --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-app/src/test/resources/application.yml @@ -0,0 +1,33 @@ +spring.devtools.restart.log-condition-evaluation-delta: false +logging.config: ./configuration/log4j2.yml +server: + username: admin + password: admin + ssl: + enabled: true + key-store-type: JKS + key-alias: nf-oam-adopter + key-store: ./configuration/ssl/nf-oam-adopter-keystore.jks + key-store-password: nf-oam-adopter + key-password: nf-oam-adopter + trust-store: ./configuration/ssl/nf-oam-adopter-truststore.jks + trust-store-password: nf-oam-adopter + enabled-protocols: TLSv1.3 + ciphers: TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_CCM_8_SHA256, TLS_AES_128_CCM_SHA256 +ves-collector: + url: someUrl + vesEncodedAuth: someAuth +http-client: + conection-timeout: 600 + response-timeout: 600 +pm-rest-manager: + synchronization-time-start: 20:00:00 + synchronization-time-frequency: 5 + mapping-config-path: mapping-configuration/pm-ves-message-mapping.yaml + ran-token-endpoint: /auth/token + ran-pm-endpoint: /pm/files + ran-time-zone-offset-endpoint: /system/timeZone +snmp-manager: + host: "0.0.0.0" + port: 10162 + mapping-config-path: mapping-configuration/fm-ves-message-mapping.yaml \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-artifacts/pom.xml b/ves-nf-oam-adopter/ves-nf-oam-adopter-artifacts/pom.xml index 63cb23f..7269b55 100644 --- a/ves-nf-oam-adopter/ves-nf-oam-adopter-artifacts/pom.xml +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-artifacts/pom.xml @@ -66,6 +66,16 @@ ves-nf-oam-adopter-snmp-manager ${project.version} + + ${project.groupId} + ves-nf-oam-adopter-pm-manager + ${project.version} + + + ${project.groupId} + ves-nf-oam-adopter-pm-sb-rest-client + ${project.version} + \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/configuration/application.yml b/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/configuration/application.yml index 6bd01fd..c409443 100644 --- a/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/configuration/application.yml +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/configuration/application.yml @@ -1,7 +1,7 @@ spring.devtools.restart.log-condition-evaluation-delta: false scheduler: - fixedDelay: 8000 - initialDelay: 4000 + fixedDelay: 16000 + initialDelay: 8000 security: auth: username: admin diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/docs/api/swagger/openapi.yaml b/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/docs/api/swagger/openapi.yaml index 3f0aaaa..629703e 100644 --- a/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/docs/api/swagger/openapi.yaml +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/docs/api/swagger/openapi.yaml @@ -48,7 +48,7 @@ paths: '401': $ref: '#/components/responses/401Error' /pm/files: - post: + get: tags: - controller summary: Read Performance Management Files @@ -67,7 +67,7 @@ paths: '401': $ref: '#/components/responses/401Error' /system/timeZone: - post: + get: tags: - controller summary: Read time zone diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/pom.xml b/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/pom.xml index 7c8c356..0869dc6 100644 --- a/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/pom.xml +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-mock/pom.xml @@ -91,7 +91,6 @@ io.swagger.codegen.v3 swagger-codegen-maven-plugin - ${swagger-codegen-maven-plugin.version} @@ -136,7 +135,7 @@ ${nexus.repository}${image.name} - ${base.image} + ${nexus.repository.mirror}${base.image} ${project.version} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-parent/pom.xml b/ves-nf-oam-adopter/ves-nf-oam-adopter-parent/pom.xml index a694efe..a200391 100644 --- a/ves-nf-oam-adopter/ves-nf-oam-adopter-parent/pom.xml +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-parent/pom.xml @@ -44,7 +44,11 @@ ../ves-nf-oam-adopter-event-notifier/target/site/jacoco-ut/jacoco.xml, ../ves-nf-oam-adopter-event-notifier/target/site/jacoco-aggregate/jacoco.xml, ../ves-nf-oam-adopter-snmp-manager/target/site/jacoco-ut/jacoco.xml, - ../ves-nf-oam-adopter-snmp-manager/target/site/jacoco-aggregate/jacoco.xml + ../ves-nf-oam-adopter-snmp-manager/target/site/jacoco-aggregate/jacoco.xml, + ../ves-nf-oam-adopter-pm-manager/target/site/jacoco-ut/jacoco.xml, + ../ves-nf-oam-adopter-pm-manager/target/site/jacoco-aggregate/jacoco.xml, + ../ves-nf-oam-adopter-pm-sb-rest-client/target/site/jacoco-ut/jacoco.xml, + ../ves-nf-oam-adopter-pm-sb-rest-client/target/site/jacoco-aggregate/jacoco.xml 3.8.0.2131 @@ -52,6 +56,7 @@ 2.6 1.9.4 2.8.6 + 30.1-jre 5.0.3 2.2.600 1.18.20 @@ -72,7 +77,8 @@ openjdk:11-jre-slim ${project.basedir}/configuration/ /o-ran-ves-adapter/ - nexus3.o-ran-sc.org:10003/o-ran-sc/ + nexus3.o-ran-sc.org:10001/ + nexus3.o-ran-sc.org:10004/o-ran-sc/ @@ -84,11 +90,6 @@ pom import - - io.swagger.core.v3 - swagger-annotations - ${swagger-annotations.version} - com.google.code.gson gson @@ -134,11 +135,21 @@ commons-beanutils ${commons-beanutils.version} + + com.google.guava + guava + ${guava.version} + com.github.spotbugs spotbugs-annotations ${spotbugs.version} + + io.swagger.core.v3 + swagger-annotations + ${swagger-annotations.version} + org.springframework.boot spring-boot-starter @@ -434,6 +445,11 @@ + + io.swagger.codegen.v3 + swagger-codegen-maven-plugin + ${swagger-codegen-maven-plugin.version} + diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/pom.xml b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/pom.xml new file mode 100644 index 0000000..02b4f98 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/pom.xml @@ -0,0 +1,108 @@ + + + + 4.0.0 + + + org.o-ran-sc.oam + ves-nf-oam-adopter-parent + 1.0.0-SNAPSHOT + ../ves-nf-oam-adopter-parent/pom.xml + + + ves-nf-oam-adopter-pm-manager + + + + ${project.groupId} + ves-nf-oam-adopter-api + + + org.apache.httpcomponents.client5 + httpclient5 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.dataformat + jackson-dataformat-csv + + + commons-io + commons-io + + + org.apache.commons + commons-configuration2 + + + commons-beanutils + commons-beanutils + + + com.google.guava + guava + 30.1-jre + + + io.reactivex.rxjava3 + rxjava + + + org.projectlombok + lombok + + + org.slf4j + slf4j-api + + + com.google.code.gson + gson + + + com.github.spotbugs + spotbugs-annotations + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-test + test + + + \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/AdaptersDeployer.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/AdaptersDeployer.java new file mode 100644 index 0000000..924373d --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/AdaptersDeployer.java @@ -0,0 +1,100 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import static org.eclipse.jdt.annotation.Checks.requireNonNull; + +import com.google.common.collect.ImmutableList; +import java.time.ZoneId; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.PerformanceManagementAdaptersDeployer; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.AlreadyPresentException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.NotFoundException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public final class AdaptersDeployer implements PerformanceManagementAdaptersDeployer, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(AdaptersDeployer.class); + + private final PerformanceManagementRestAgentFactory pmRestAgentFactory; + private final Map adapters = new ConcurrentHashMap<>(); + + @Autowired + public AdaptersDeployer(final PerformanceManagementRestAgentFactory pmRestAgentFactory) { + this.pmRestAgentFactory = pmRestAgentFactory; + } + + @Override + public synchronized void create(final String hostIpAddress, final String username, final String password) + throws AlreadyPresentException { + LOG.info("Create device PM adapter {}", hostIpAddress); + if (adapters.get(hostIpAddress) != null) { + throw new AlreadyPresentException(hostIpAddress); + } + final Adapter adapter = + Adapter.builder().username(username).password(password).hostIpAddress(hostIpAddress).build(); + final PerformanceManagementRestAgent pmRestAgent = + pmRestAgentFactory.createPerformanceManagementRestAgent(adapter).blockingGet(); + pmRestAgent.init(); + adapters.put(hostIpAddress, pmRestAgent); + } + + @Override + public synchronized void delete(final String host) throws NotFoundException { + LOG.info("Adapter PM adapter removed {}", requireNonNull(host)); + final PerformanceManagementRestAgent adapter = adapters.remove(host); + if (adapter == null) { + throw new NotFoundException(host); + } + adapter.close(); + } + + @Override + public List getAll() { + return ImmutableList.copyOf(adapters.keySet()); + } + + @Override + public ZoneId getTimeZone(final String host) { + LOG.debug("Read time zone for {}", host); + return Optional.ofNullable(adapters.get(host)).map( + PerformanceManagementRestAgent::getTimeZone).orElse(null); + } + + @Override + public synchronized void close() { + for (final String host : ImmutableList.copyOf(adapters.keySet())) { + try { + delete(host); + } catch (final Exception e) { + LOG.warn("Failed to delete device PM adapter {}", host); + } + } + adapters.clear(); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementMapperConfigProvider.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementMapperConfigProvider.java new file mode 100644 index 0000000..b7c24f8 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementMapperConfigProvider.java @@ -0,0 +1,85 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import static java.util.Objects.requireNonNull; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import java.io.IOException; +import java.io.StringWriter; +import java.net.URI; +import java.nio.file.Paths; +import javax.annotation.PostConstruct; +import org.apache.commons.configuration2.YAMLConfiguration; +import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent; +import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder; +import org.apache.commons.configuration2.builder.fluent.Parameters; +import org.apache.commons.configuration2.event.EventListener; +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.VesMappingConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class PerformanceManagementMapperConfigProvider { + + private static final Logger LOG = LoggerFactory.getLogger(PerformanceManagementMapperConfigProvider.class); + + private static final ObjectMapper YAML_READER = new ObjectMapper(new YAMLFactory()); + @Value("${pm-rest-manager.mapping-config-path:#{null}}") + private String mappingFilePath; + private ReloadingFileBasedConfigurationBuilder builder; + + @Autowired + public PerformanceManagementMapperConfigProvider() { + + } + + /** + * Initialize Service. + */ + @PostConstruct + public void init() throws IOException, ConfigurationException { + requireNonNull(mappingFilePath); + final URI filePath = Paths.get(mappingFilePath).toUri(); + builder = new ReloadingFileBasedConfigurationBuilder<>(YAMLConfiguration.class) + .configure(new Parameters().hierarchical().setURL(filePath.toURL())); + builder.addEventListener(ConfigurationBuilderEvent.CONFIGURATION_REQUEST, (EventListener) event -> { + builder.getReloadingController().checkForReloading(null); + LOG.debug("Reloading {}", filePath.toString()); + }); + //Test initial configuration + builder.getConfiguration(); + } + + /** + * Provide VES Mapping configuration. + */ + public VesMappingConfiguration getVesMappingConfiguration() throws ConfigurationException, IOException { + final YAMLConfiguration configuration = builder.getConfiguration(); + final StringWriter output = new StringWriter(); + configuration.write(output); + return YAML_READER.readValue(output.toString(), VesMappingConfiguration.class); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgent.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgent.java new file mode 100644 index 0000000..66693fc --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgent.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import java.time.Duration; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public final class PerformanceManagementRestAgent implements AutoCloseable { + + private static final DateTimeFormatter TIME_INPUT_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss"); + private final ScheduledExecutorService scheduler; + private final Runnable pmAgent; + private final LocalTime synchronizationTimeStart; + private final int synchronizationTimeFrequency; + private final ZoneId zoneId; + + + PerformanceManagementRestAgent(final Runnable pmAgent, final String synchronizationTimeStart, + final int synchronizationTimeFrequency, final ZoneId zoneId) { + this.scheduler = Executors.newSingleThreadScheduledExecutor(); + this.pmAgent = pmAgent; + this.synchronizationTimeStart = LocalTime.parse(synchronizationTimeStart, TIME_INPUT_FORMAT); + this.synchronizationTimeFrequency = synchronizationTimeFrequency; + this.zoneId = zoneId; + } + + /** + * Initialize service at fixed rate. + */ + public void init() { + final long initialDelay = initialDelay(); + scheduler.scheduleAtFixedRate(pmAgent, initialDelay, synchronizationTimeFrequency, TimeUnit.SECONDS); + } + + private long initialDelay() { + final ZonedDateTime now = ZonedDateTime.now(zoneId); + + ZonedDateTime nextRun = now + .withHour(synchronizationTimeStart.getHour()) + .withMinute(synchronizationTimeStart.getMinute()) + .withSecond(synchronizationTimeStart.getSecond()); + if (now.compareTo(nextRun) > 0) { + nextRun = nextRun.plusSeconds(synchronizationTimeFrequency); + } + final Duration duration = Duration.between(now, nextRun); + return duration.getSeconds(); + } + + public ZoneId getTimeZone() { + return zoneId; + } + + @Override + public void close() { + scheduler.shutdown(); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgentFactory.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgentFactory.java new file mode 100644 index 0000000..0ebaa6c --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementRestAgentFactory.java @@ -0,0 +1,97 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.schedulers.Schedulers; +import org.o.ran.oam.nf.oam.adopter.api.VesEventNotifier; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.HttpRestClient; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.mapper.PerformanceManagementFile2VesMapper; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.properties.PerformanceManagementManagerProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PerformanceManagementRestAgentFactory { + private static final Logger LOG = LoggerFactory.getLogger(PerformanceManagementRestAgentFactory.class); + + private final VesEventNotifier eventListener; + private final PerformanceManagementManagerProperties properties; + private final PerformanceManagementFile2VesMapper pmFileMapper; + private final HttpRestClient httpRestClient; + + /** + * Default constructor. + */ + public PerformanceManagementRestAgentFactory(final VesEventNotifier eventListener, + final PerformanceManagementFile2VesMapper pmFileMapper, + final PerformanceManagementManagerProperties properties, final HttpRestClient httpRestClient) { + this.eventListener = eventListener; + this.pmFileMapper = pmFileMapper; + this.properties = properties; + this.httpRestClient = httpRestClient; + } + + /** + * Generates new PM Agent which will get pm files via rest at specific time each day and + * send it as CommonEventFormat302ONAP event via rest. + * @param adapter IP address fo the adapter, adapter login username, adapter login password + * @return PMRestAgent + */ + public final Single createPerformanceManagementRestAgent(final Adapter adapter) { + return httpRestClient.getTimeZone(adapter).map(timeZone -> { + final PerformanceManagementAgentRunnable pmAgentRunnable = + new PerformanceManagementAgentRunnable(httpRestClient, eventListener, pmFileMapper, adapter); + return new PerformanceManagementRestAgent(pmAgentRunnable, properties.getSynchronizationTimeStart(), + properties.getSynchronizationTimeFrequency(), timeZone); + }); + } + + private static class PerformanceManagementAgentRunnable implements Runnable { + final HttpRestClient httpClient; + private final VesEventNotifier pmEventListener; + private final PerformanceManagementFile2VesMapper pmFileMapper; + private final Adapter adapter; + + public PerformanceManagementAgentRunnable(final HttpRestClient httpClient, + final VesEventNotifier pmEventListener, + final PerformanceManagementFile2VesMapper pmFileMapper, final Adapter adapter) { + this.httpClient = httpClient; + this.pmEventListener = pmEventListener; + this.pmFileMapper = pmFileMapper; + this.adapter = adapter; + } + + @Override + public synchronized void run() { + final String hostIp = adapter.getHostIpAddress(); + httpClient.readFiles(adapter) + .flatMap(zip -> pmFileMapper.map(zip, hostIp)) + .flatMapCompletable(events -> Observable.fromIterable(events) + .concatMapCompletable(pmEventListener::notifyEvents)) + .doOnSubscribe(result -> LOG.info("PM VES notification forwarding for adapter {} started", hostIp)) + .doOnComplete(() -> LOG.info("PM VES notification forwarding for adapter {} finished", hostIp)) + .doOnError(error -> LOG.warn("PM VES notification forwarding for adapter {} failed", hostIp)) + .subscribeOn(Schedulers.single()) + .subscribe(); + } + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/api/HttpRestClient.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/api/HttpRestClient.java new file mode 100644 index 0000000..71a27ea --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/api/HttpRestClient.java @@ -0,0 +1,13 @@ +package org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api; + +import io.reactivex.rxjava3.core.Single; +import java.time.ZoneId; +import java.util.zip.ZipInputStream; +import org.eclipse.jdt.annotation.NonNull; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; + +public interface HttpRestClient { + @NonNull Single readFiles(@NonNull Adapter adapter); + + @NonNull Single getTimeZone(@NonNull Adapter adapter); +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/api/PerformanceManagementAdaptersDeployer.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/api/PerformanceManagementAdaptersDeployer.java new file mode 100644 index 0000000..01be898 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/api/PerformanceManagementAdaptersDeployer.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.api; + +import java.time.ZoneId; +import java.util.List; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.AlreadyPresentException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.NotFoundException; + +public interface PerformanceManagementAdaptersDeployer { + + /** + * Creates PM Adapter. + * + * @param hostIpAddress adapter ip address + * @param username mechid username + * @param password mechid password + * @throws AlreadyPresentException if already present + */ + void create(@NonNull String hostIpAddress, @NonNull String username, @NonNull String password) + throws AlreadyPresentException; + + /** + * Removes PM Adapter by host ip address. + * + * @param host ip address + * @throws NotFoundException if not present + */ + void delete(@NonNull String host) throws NotFoundException; + + /** + * Returns list of Adapters host Ip. + */ + @NonNull List getAll(); + + /** + * Returns time zone of specific device. + */ + @Nullable ZoneId getTimeZone(@NonNull String host); +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/configurations/PerformanceManagementRestManagerConfig.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/configurations/PerformanceManagementRestManagerConfig.java new file mode 100644 index 0000000..0a88e80 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/configurations/PerformanceManagementRestManagerConfig.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.configurations; + +import org.o.ran.oam.nf.oam.adopter.api.VesEventNotifier; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.PerformanceManagementRestAgentFactory; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.HttpRestClient; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.mapper.PerformanceManagementFile2VesMapper; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.properties.PerformanceManagementManagerProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties +public class PerformanceManagementRestManagerConfig { + private final PerformanceManagementManagerProperties pmManagerProperties; + private final VesEventNotifier eventListener; + private final PerformanceManagementFile2VesMapper pmFileMapper; + + /** + * Default constructor. + */ + @Autowired + public PerformanceManagementRestManagerConfig(final VesEventNotifier eventListener, + final PerformanceManagementFile2VesMapper pmFileMapper, + final PerformanceManagementManagerProperties pmManagerProperties) { + this.eventListener = eventListener; + this.pmFileMapper = pmFileMapper; + this.pmManagerProperties = pmManagerProperties; + } + + @Bean + PerformanceManagementRestAgentFactory getPerformanceManagementRestManagerFactoryService( + final HttpRestClient httpRestClient) { + return new PerformanceManagementRestAgentFactory(eventListener, pmFileMapper, pmManagerProperties, + httpRestClient); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/AlreadyPresentException.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/AlreadyPresentException.java new file mode 100644 index 0000000..9199daa --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/AlreadyPresentException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions; + +public class AlreadyPresentException extends PerformanceManagementException { + private static final long serialVersionUID = -1852996415384288431L; + + public AlreadyPresentException(final String adapter) { + super("Adapter " + adapter + " already present."); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/NotFoundException.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/NotFoundException.java new file mode 100644 index 0000000..4179fb9 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/NotFoundException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions; + +public class NotFoundException extends PerformanceManagementException { + private static final long serialVersionUID = -1852996415384288431L; + + public NotFoundException(final String adapter) { + super("Adapter " + adapter + " is not present."); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/PerformanceManagementEmptyOutputException.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/PerformanceManagementEmptyOutputException.java new file mode 100644 index 0000000..492e13c --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/PerformanceManagementEmptyOutputException.java @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions; + +/** + * Object already exists exception. + */ +public class PerformanceManagementEmptyOutputException extends PerformanceManagementException { + + private static final long serialVersionUID = 1L; + + /** + * Create object already exists exception. + * + * @param message exception message + */ + public PerformanceManagementEmptyOutputException(final String message) { + super(message); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/PerformanceManagementException.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/PerformanceManagementException.java new file mode 100644 index 0000000..f39dac8 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/PerformanceManagementException.java @@ -0,0 +1,41 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions; + +/** + * Object already exists exception. + */ +public class PerformanceManagementException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * Create object already exists exception. + * + * @param message exception message + */ + public PerformanceManagementException(final String message) { + super(message); + } + + public PerformanceManagementException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/TokenGenerationException.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/TokenGenerationException.java new file mode 100644 index 0000000..6441e98 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/TokenGenerationException.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions; + +/** + * Object already exists exception. + */ +public class TokenGenerationException extends PerformanceManagementException { + + private static final long serialVersionUID = 1L; + + /** + * Create object already exists exception. + * + * @param message exception message + */ + public TokenGenerationException(final String message) { + super(message); + } + +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/ZoneIdException.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/ZoneIdException.java new file mode 100644 index 0000000..4552533 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/exceptions/ZoneIdException.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions; + +/** + * Object already exists exception. + */ +public class ZoneIdException extends PerformanceManagementException { + + private static final long serialVersionUID = 1L; + + /** + * Create object already exists exception. + * + * @param message exception message + */ + public ZoneIdException(final String message, final Throwable cause) { + super(message, cause); + } + +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/CommonEventHeaderHandler.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/CommonEventHeaderHandler.java new file mode 100644 index 0000000..7049285 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/CommonEventHeaderHandler.java @@ -0,0 +1,83 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.mapper; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.o.ran.oam.nf.oam.adopter.api.CommonEventHeader; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.CsvConfiguration; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.VesMappingConfiguration; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +final class CommonEventHeaderHandler { + private static final String PM_NOTIFICATIONS = "PM_Notification"; + + static CommonEventHeader toCommonEventHeader(final VesMappingConfiguration config, final String hostIp, + final CsvConfiguration csv, final Map record, final int sequence) { + final CommonEventHeader header = new CommonEventHeader(); + setMandatoryFields(config, hostIp, csv, header, record, sequence); + setOptionalFields(config, header); + return header; + } + + private static void setOptionalFields(final VesMappingConfiguration config, final CommonEventHeader header) { + header.setNfVendorName(Optional.ofNullable(config.getNfVendorName()).orElse(null)); + header.setReportingEntityId(config.getReportingEntityId()); + header.setNfNamingCode(null); //NOP + header.setNfcNamingCode(null); //NOP + header.setTimeZoneOffset(null); //NOP + } + + private static void setMandatoryFields(final VesMappingConfiguration config, final String hostIp, + final CsvConfiguration csv, final CommonEventHeader header, final Map record, + final int sequence) { + header.setDomain(CommonEventHeader.Domain.MEASUREMENT); + header.setEventName(CommonEventHeader.Domain.FAULT.name() + + "_" + config.getReportingEntityName() + + "_" + Optional.ofNullable(config.getEventName()).orElse(PM_NOTIFICATIONS)); + header.setStartEpochMicrosec(System.currentTimeMillis()); + header.setLastEpochMicrosec(System.currentTimeMillis()); + header.setPriority(CommonEventHeader.Priority.fromValue(config.getPriority())); + header.setReportingEntityName(config.getReportingEntityName()); + header.setSequence((long) sequence); + final String sourceNameField = csv.getSourceName(); + final String sourceNameRecordValue = Optional.ofNullable(sourceNameField).map(record::get).orElse(hostIp); + final Optional optRegex = Optional.ofNullable(csv.getSourceNameRegex()); + header.setSourceName(optRegex.map(regex -> sourceNameRecordValue.replaceAll(regex, "")) + .orElse(sourceNameRecordValue)); + header.setVersion(CommonEventHeader.Version._4_0); + header.setVesEventListenerVersion(Optional.ofNullable(config.getVesEventListenerVersion()) + .map(CommonEventHeader.VesEventListenerVersion::fromValue) + .orElse(CommonEventHeader.VesEventListenerVersion._7_1)); + + final List eventId = csv.getEventId(); + final String keyIdConcat = eventId.stream() + .filter(record::containsKey) + .map(record::get) + .collect(Collectors.joining()); + header.setEventId(UUID.nameUUIDFromBytes(keyIdConcat.getBytes(StandardCharsets.UTF_8)).toString()); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/MeasurementFieldsHandler.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/MeasurementFieldsHandler.java new file mode 100644 index 0000000..166af50 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/MeasurementFieldsHandler.java @@ -0,0 +1,82 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.mapper; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.o.ran.oam.nf.oam.adopter.api.MeasurementFields; +import org.o.ran.oam.nf.oam.adopter.api.NamedHashMap; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.CsvConfiguration; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.VesMappingConfiguration; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +final class MeasurementFieldsHandler { + private static void setOptionalsFields(final MeasurementFields measurementFields, final Map records, + final VesMappingConfiguration config) { + final CsvConfiguration csv = config.getCsv(); + measurementFields.setAdditionalFields(csv.getAdditionalFields() + .stream().filter(records::containsKey) + .collect(Collectors.toMap(Function.identity(), records::get))); + + final NamedHashMap namedHashMap = new NamedHashMap(); + namedHashMap.setName(csv.getAdditionalMeasurementsName()); + namedHashMap.setHashMap(csv.getAdditionalMeasurements().stream() + .filter(records::containsKey) + .collect(Collectors.toMap(Function.identity(), records::get))); + measurementFields.setAdditionalMeasurements(Collections.singletonList(namedHashMap)); + measurementFields.setAdditionalObjects(null); + measurementFields.setCodecUsageArray(null); + measurementFields.setConfiguredEntities(null); + measurementFields.setCpuUsageArray(null); + measurementFields.setDiskUsageArray(null); + measurementFields.setFeatureUsageArray(null); + measurementFields.setFilesystemUsageArray(null); + measurementFields.setHugePagesArray(null); + measurementFields.setIpmi(null); + measurementFields.setLatencyDistribution(null); + measurementFields.setLoadArray(null); + measurementFields.setMachineCheckExceptionArray(null); + measurementFields.setMeanRequestLatency(null); + measurementFields.setMemoryUsageArray(null); + measurementFields.setNfcScalingMetric(null); + measurementFields.setNicPerformanceArray(null); + measurementFields.setNumberOfMediaPortsInUse(null); + measurementFields.setProcessStatsArray(null); + measurementFields.setRequestRate(null); + } + + static MeasurementFields toMeasurementFields(final VesMappingConfiguration config, + final Map records) { + final MeasurementFields measurementFields = new MeasurementFields(); + setMandatoryFields(measurementFields, config); + setOptionalsFields(measurementFields, records, config); + return measurementFields; + } + + private static void setMandatoryFields(final MeasurementFields measurementFields, + final VesMappingConfiguration config) { + measurementFields.setMeasurementFieldsVersion(MeasurementFields.MeasurementFieldsVersion._4_0); + measurementFields.setMeasurementInterval(config.getMeasurementInterval()); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/PerformanceManagementFile2VesMapper.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/PerformanceManagementFile2VesMapper.java new file mode 100644 index 0000000..6036a93 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/mapper/PerformanceManagementFile2VesMapper.java @@ -0,0 +1,127 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.mapper; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.reactivex.rxjava3.core.Single; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import org.o.ran.oam.nf.oam.adopter.api.CommonEventFormat302ONAP; +import org.o.ran.oam.nf.oam.adopter.api.Event; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.PerformanceManagementMapperConfigProvider; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.CsvConfiguration; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.VesMappingConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class PerformanceManagementFile2VesMapper { + private static final Logger LOG = LoggerFactory.getLogger(PerformanceManagementFile2VesMapper.class); + + private static final String CSV_EXTENSION = ".csv"; + private final PerformanceManagementMapperConfigProvider pmConfigProvider; + + @Autowired + public PerformanceManagementFile2VesMapper(final PerformanceManagementMapperConfigProvider pmConfigProvider) { + this.pmConfigProvider = pmConfigProvider; + } + + /** + * Translate CSV in ZipInputStream format to list of CommonEventFormat302ONAP events. + * + * @param zipInputStream csv + * @param hostIp source Ip Address + * @return CommonEventFormat302ONAP events + */ + @SuppressFBWarnings("REC_CATCH_EXCEPTION") + public Single> map(final ZipInputStream zipInputStream, final String hostIp) { + LOG.info("Converting ZIP files to VES Message started"); + final List listOfNotifications = new ArrayList<>(); + final CsvSchema schema = CsvSchema.emptySchema().withHeader(); + final CsvMapper mapper = new CsvMapper(); + mapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false); + try { + ZipEntry entry; + final VesMappingConfiguration mappingConfiguration = pmConfigProvider.getVesMappingConfiguration(); + while ((entry = zipInputStream.getNextEntry()) != null) { + final String entryName = entry.getName(); + if (!entryName.endsWith(CSV_EXTENSION)) { + return Single.error(new Exception("Wrong file type :" + entryName)); + } + + final Iterator> iterator = + mapper.readerFor(Map.class).with(schema).readValues(zipInputStream); + final List> mappedEvents = toEvent(mappingConfiguration, hostIp, iterator); + + mappedEvents.forEach(mapped -> { + final CommonEventFormat302ONAP eventFormat = new CommonEventFormat302ONAP(); + eventFormat.setEventList(mapped); + listOfNotifications.add(eventFormat); + }); + } + } catch (final Exception e) { + return Single.error(new Exception("Failed to process file", e)); + } finally { + try { + zipInputStream.closeEntry(); + } catch (final IOException e) { + LOG.warn("Failed to close zip stream", e); + } + } + LOG.info("Converting ZIP files to VES Message finished"); + return Single.just(listOfNotifications); + } + + private static List> toEvent(final VesMappingConfiguration mappingConfiguration, final String hostIp, + final Iterator> iterator) { + final List> globalList = new ArrayList<>(); + final int batchSize = mappingConfiguration.getBatchSize(); + int sequence = 0; + List events = new ArrayList<>(); + final CsvConfiguration csv = mappingConfiguration.getCsv(); + while (iterator.hasNext()) { + final Event event = new Event(); + final Map record = iterator.next(); + event.setCommonEventHeader( + CommonEventHeaderHandler.toCommonEventHeader(mappingConfiguration, hostIp, csv, record, sequence)); + event.setMeasurementFields(MeasurementFieldsHandler.toMeasurementFields(mappingConfiguration, record)); + events.add(event); + sequence++; + if (sequence % batchSize == 0) { + globalList.add(events); + events = new ArrayList<>(); + } + } + if (!events.isEmpty()) { + globalList.add(events); + } + return globalList; + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/Adapter.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/Adapter.java new file mode 100644 index 0000000..555634b --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/Adapter.java @@ -0,0 +1,34 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NonNull; + +@EqualsAndHashCode +@Getter +@Builder +public final class Adapter { + private @NonNull final String hostIpAddress; + private @NonNull final String username; + private @NonNull final String password; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/CsvConfiguration.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/CsvConfiguration.java new file mode 100644 index 0000000..cdb7617 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/CsvConfiguration.java @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class CsvConfiguration { + @JsonProperty("additional-fields") + private List additionalFields; + @JsonProperty("additional-measurements-name") + private String additionalMeasurementsName; + @JsonProperty("additional-measurements") + private List additionalMeasurements; + @JsonProperty("event-id") + private List eventId; + @JsonProperty("source-name") + private String sourceName; + @JsonProperty("source-name-regex") + private String sourceNameRegex; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/VesMappingConfiguration.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/VesMappingConfiguration.java new file mode 100644 index 0000000..3d4ea11 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/pojos/VesMappingConfiguration.java @@ -0,0 +1,49 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class VesMappingConfiguration { + @JsonProperty("reporting-entity-name") + private String reportingEntityName; + @JsonProperty("reporting-entity-id") + private String reportingEntityId; + @JsonProperty("nf-vendor-name") + private String nfVendorName; + @JsonProperty("event-source-type") + private String eventSourceType; + @JsonProperty("event-name") + private String eventName; + @JsonProperty("measurement-interval") + private Long measurementInterval; + @JsonProperty("csv") + private CsvConfiguration csv; + @JsonProperty("batch-size") + private int batchSize; + @JsonProperty("priority") + private String priority; + @JsonProperty("ves-event-listener-version") + private String vesEventListenerVersion; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/properties/PerformanceManagementManagerProperties.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/properties/PerformanceManagementManagerProperties.java new file mode 100644 index 0000000..2a3af54 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/properties/PerformanceManagementManagerProperties.java @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager.properties; + +import javax.validation.constraints.NotEmpty; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "pm-rest-manager") +@Data +@NoArgsConstructor +public class PerformanceManagementManagerProperties { + @NotEmpty + private String synchronizationTimeStart; + private int synchronizationTimeFrequency; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/HttpRestClientMock.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/HttpRestClientMock.java new file mode 100644 index 0000000..095eafd --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/HttpRestClientMock.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import io.reactivex.rxjava3.core.Single; +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.time.ZoneId; +import java.util.zip.ZipInputStream; +import org.eclipse.jdt.annotation.NonNull; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.HttpRestClient; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; + +public class HttpRestClientMock implements HttpRestClient { + + @Override + public Single readFiles(@NonNull final Adapter adapter) { + final InputStream file = HttpRestClientMock.class.getResourceAsStream("/zip/nfOamAdapter1.zip"); + if (file == null) { + return Single.error(new Exception("Failed to read test file")); + } + final BufferedInputStream bis = new BufferedInputStream(file); + return Single.just(new ZipInputStream(bis)); + } + + @Override + public @NonNull Single getTimeZone(@NonNull final Adapter adapter) { + return Single.just(ZoneId.of("+02:00")); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/JsonUtils.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/JsonUtils.java new file mode 100644 index 0000000..91bfb47 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/JsonUtils.java @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import lombok.experimental.UtilityClass; +import org.apache.commons.io.IOUtils; + +@UtilityClass +final class JsonUtils { + private static final List WHITE_LIST = Arrays.asList("eventId", "startEpochMicrosec", "lastEpochMicrosec"); + private static final String EVENT_LIST = "eventList"; + private static final String COMMON_EVENT_HEADER = "commonEventHeader"; + + static String readJson(final String url) throws IOException { + return IOUtils.toString(JsonUtils.class.getResourceAsStream(url), StandardCharsets.UTF_8); + } + + public static void compareResult(final String expected, final String actual) { + final JsonObject expectedJO = JsonParser.parseString(expected).getAsJsonObject(); + final JsonObject actualJO = JsonParser.parseString(actual).getAsJsonObject(); + removeCommonEventHeaderFields(expectedJO.get(EVENT_LIST).getAsJsonArray(), + actualJO.get(EVENT_LIST).getAsJsonArray(), WHITE_LIST); + assertEquals(expectedJO, actualJO); + } + + private static void removeCommonEventHeaderFields(final JsonArray expectedJO, final JsonArray actualJO, + final List asList) { + asList.forEach(wipe -> { + expectedJO.forEach(jsonElement -> removeCommonEventHeaderFields(jsonElement, wipe)); + actualJO.forEach(jsonElement -> removeCommonEventHeaderFields(jsonElement, wipe)); + }); + } + + private static void removeCommonEventHeaderFields(final JsonElement jsonElement, final String wipe) { + jsonElement.getAsJsonObject().getAsJsonObject(COMMON_EVENT_HEADER).remove(wipe); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementManagerTest.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementManagerTest.java new file mode 100644 index 0000000..eb0112e --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/PerformanceManagementManagerTest.java @@ -0,0 +1,140 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import static java.lang.Thread.sleep; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.extension.ExtendWith; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.PerformanceManagementAdaptersDeployer; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.AlreadyPresentException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.NotFoundException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.mapper.PerformanceManagementFile2VesMapper; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.properties.PerformanceManagementManagerProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = {VesEventNotifierMock.class, PerformanceManagementMapperConfigProvider.class, + PerformanceManagementFile2VesMapper.class, PerformanceManagementAdaptersDeployer.class}) +public class PerformanceManagementManagerTest { + + @Autowired + @Qualifier("test") + private VesEventNotifierMock eventListener; + @Autowired + private PerformanceManagementFile2VesMapper fileMapper; + private PerformanceManagementAdaptersDeployer deployer; + + /** + * Initialize test. + */ + @BeforeEach + public void init() { + final HttpRestClientMock httpRestClientMock = new HttpRestClientMock(); + final PerformanceManagementManagerProperties properties = new PerformanceManagementManagerProperties(); + final ZonedDateTime now = ZonedDateTime.now(ZoneId.of("+02:00")).plusSeconds(5); + final String formattedString = now.format(DateTimeFormatter.ofPattern("HH:mm:ss")); + properties.setSynchronizationTimeStart(formattedString); + properties.setSynchronizationTimeFrequency(30); + deployer = new AdaptersDeployer( + new PerformanceManagementRestAgentFactory(eventListener, fileMapper, properties, httpRestClientMock)); + } + + @Test + @Timeout(value = 10000, unit = TimeUnit.MILLISECONDS) + public void testMapping() throws IOException, InterruptedException, AlreadyPresentException { + assertTrue(deployer.getAll().isEmpty()); + deployer.create("172.0.10.2", "admin", "admin"); + assertFalse(deployer.getAll().isEmpty()); + + final String expected = JsonUtils.readJson("/json/PMVESMessage.json"); + final List notifications = getVesNotification(eventListener, 2); + final String actual = notifications.get(0); + JsonUtils.compareResult(expected, actual); + } + + @Test + public void testDelete() throws AlreadyPresentException, NotFoundException { + assertTrue(deployer.getAll().isEmpty()); + deployer.create("172.0.10.2", "admin", "admin"); + assertFalse(deployer.getAll().isEmpty()); + + deployer.delete("172.0.10.2"); + assertTrue(deployer.getAll().isEmpty()); + } + + @Test + public void testAlreadyPresent() throws AlreadyPresentException { + assertTrue(deployer.getAll().isEmpty()); + deployer.create("172.0.10.2", "admin", "admin"); + assertFalse(deployer.getAll().isEmpty()); + + final Exception alreadyPresentException = assertThrows(AlreadyPresentException.class, + () -> deployer.create("172.0.10.2", "admin", "admin")); + assertEquals(alreadyPresentException.getMessage(), "Adapter 172.0.10.2 already present."); + } + + @Test + public void testNotPresent() { + final Exception exception = assertThrows(NotFoundException.class, () -> deployer.delete("172.0.10.2")); + assertEquals(exception.getMessage(), "Adapter 172.0.10.2 is not present."); + } + + @Test + public void testTimeZone() throws AlreadyPresentException { + deployer.create("172.0.10.2", "admin", "admin"); + assertEquals(deployer.getTimeZone("172.0.10.2"), ZoneId.of("+02:00")); + } + + private static List getVesNotification(final VesEventNotifierMock listener, final int expectedSize) + throws InterruptedException { + List events = null; + for (int i = 0; i < 100000; i++) { + sleep(1000); + events = listener.getEvents(); + if (events != null && !events.isEmpty() && events.size() == expectedSize) { + break; + } + } + return events; + } + + @AfterEach + public final void after() { + ((AdaptersDeployer) deployer).close(); + assertTrue(deployer.getAll().isEmpty()); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/VesEventNotifierMock.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/VesEventNotifierMock.java new file mode 100644 index 0000000..ff79438 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/rest/manager/VesEventNotifierMock.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.rest.manager; + +import com.google.gson.Gson; +import io.reactivex.rxjava3.core.Completable; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.o.ran.oam.nf.oam.adopter.api.CommonEventFormat302ONAP; +import org.o.ran.oam.nf.oam.adopter.api.VesEventNotifier; +import org.springframework.stereotype.Service; + +@Service("test") +final class VesEventNotifierMock implements VesEventNotifier { + + private static final Gson GSON = new Gson(); + private final List event = new ArrayList<>(); + + @Override + public synchronized Completable notifyEvents(final CommonEventFormat302ONAP event) { + this.event.add(event); + return Completable.complete(); + } + + protected synchronized List getEvents() { + return event.stream().map(e -> GSON.toJson(e, CommonEventFormat302ONAP.class)).collect(Collectors.toList()); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/application.yaml b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/application.yaml new file mode 100644 index 0000000..ea580db --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/application.yaml @@ -0,0 +1,4 @@ +pm-rest-manager: + synchronization-time-start: "00:05:00" + synchronization-time-frequency: 60 + mapping-config-path: "src/test/resources/pm-ves-message-mapping.yaml" diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/json/PMVESMessage.json b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/json/PMVESMessage.json new file mode 100644 index 0000000..c9c2b6b --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/json/PMVESMessage.json @@ -0,0 +1,160 @@ +{ + "eventList":[ + { + "commonEventHeader":{ + "domain":"measurement", + "eventId":"ba10db33-9e27-3296-9bfd-a8d232bbe0a8", + "eventName":"FAULT_NF-OAM-ADOPTER_PM_Notification", + "lastEpochMicrosec":1618483581744, + "nfVendorName":"SOME-VENDOR", + "priority":"High", + "reportingEntityId":"ONAP-NF-OAM-SOME-VENDOR-ADAPTER", + "reportingEntityName":"NF-OAM-ADOPTER", + "sequence":0, + "sourceName":"OAM-BOX", + "startEpochMicrosec":1618483581744, + "version":"4.0", + "vesEventListenerVersion":"7.1" + }, + "measurementFields":{ + "additionalFields":{ + "PortId":"2", + "Time":"12:02:12 AM", + "Date":"15/4/2021", + "Name":"OAM-BOX" + }, + "additionalMeasurements":[ + { + "name":"Port measurements", + "hashMap":{ + "C_Parameter":"y26", + "A_Parameter":"1100", + "E_Parameter":"+10.2", + "B_Parameter":"0.5", + "D_Parameter":"x25" + } + } + ], + "measurementInterval":40, + "measurementFieldsVersion":"4.0" + } + }, + { + "commonEventHeader":{ + "domain":"measurement", + "eventId":"f75fd549-18dc-389c-90b6-f975f3ff2a70", + "eventName":"FAULT_NF-OAM-ADOPTER_PM_Notification", + "lastEpochMicrosec":1618483581763, + "nfVendorName":"SOME-VENDOR", + "priority":"High", + "reportingEntityId":"ONAP-NF-OAM-SOME-VENDOR-ADAPTER", + "reportingEntityName":"NF-OAM-ADOPTER", + "sequence":1, + "sourceName":"OAM-BOX", + "startEpochMicrosec":1618483581763, + "version":"4.0", + "vesEventListenerVersion":"7.1" + }, + "measurementFields":{ + "additionalFields":{ + "PortId":"2", + "Time":"12:02:52 AM", + "Date":"15/4/2021", + "Name":"OAM-BOX" + }, + "additionalMeasurements":[ + { + "name":"Port measurements", + "hashMap":{ + "C_Parameter":"y26", + "A_Parameter":"2100", + "E_Parameter":"+10.01", + "B_Parameter":"0.5", + "D_Parameter":"x25" + } + } + ], + "measurementInterval":40, + "measurementFieldsVersion":"4.0" + } + }, + { + "commonEventHeader":{ + "domain":"measurement", + "eventId":"da259c3e-b66d-311d-9fb9-946b241f2fed", + "eventName":"FAULT_NF-OAM-ADOPTER_PM_Notification", + "lastEpochMicrosec":1618483581763, + "nfVendorName":"SOME-VENDOR", + "priority":"High", + "reportingEntityId":"ONAP-NF-OAM-SOME-VENDOR-ADAPTER", + "reportingEntityName":"NF-OAM-ADOPTER", + "sequence":2, + "sourceName":"OAM-BOX", + "startEpochMicrosec":1618483581763, + "version":"4.0", + "vesEventListenerVersion":"7.1" + }, + "measurementFields":{ + "additionalFields":{ + "PortId":"2", + "Time":"12:03:32 AM", + "Date":"15/4/2021", + "Name":"OAM-BOX" + }, + "additionalMeasurements":[ + { + "name":"Port measurements", + "hashMap":{ + "C_Parameter":"y26", + "A_Parameter":"3100", + "E_Parameter":"+10.02", + "B_Parameter":"0.5", + "D_Parameter":"x25" + } + } + ], + "measurementInterval":40, + "measurementFieldsVersion":"4.0" + } + }, + { + "commonEventHeader":{ + "domain":"measurement", + "eventId":"e0bedb4a-4ded-3480-92c4-9c8cec77b28e", + "eventName":"FAULT_NF-OAM-ADOPTER_PM_Notification", + "lastEpochMicrosec":1618483581764, + "nfVendorName":"SOME-VENDOR", + "priority":"High", + "reportingEntityId":"ONAP-NF-OAM-SOME-VENDOR-ADAPTER", + "reportingEntityName":"NF-OAM-ADOPTER", + "sequence":3, + "sourceName":"OAM-BOX", + "startEpochMicrosec":1618483581764, + "version":"4.0", + "vesEventListenerVersion":"7.1" + }, + "measurementFields":{ + "additionalFields":{ + "PortId":"2", + "Time":"12:04:12 AM", + "Date":"15/4/2021", + "Name":"OAM-BOX" + }, + "additionalMeasurements":[ + { + "name":"Port measurements", + "hashMap":{ + "C_Parameter":"y26", + "A_Parameter":"4100", + "E_Parameter":"+10.03", + "B_Parameter":"0.5", + "D_Parameter":"x25" + } + } + ], + "measurementInterval":40, + "measurementFieldsVersion":"4.0" + } + } + ] +} \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/pm-ves-message-mapping.yaml b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/pm-ves-message-mapping.yaml new file mode 100644 index 0000000..aaeac4e --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/pm-ves-message-mapping.yaml @@ -0,0 +1,26 @@ +reporting-entity-name: "NF-OAM-ADOPTER" +reporting-entity-id: "ONAP-NF-OAM-SOME-VENDOR-ADAPTER" +nf-vendor-name: "SOME-VENDOR" +event-source-type: "SNMP Agent" +event-name: "PM_Notification" +measurement-interval: 40 +priority: "High" +batch-size: 5 +csv: + source-name: Name + event-id: + - PortId + - Date + - Time + additional-fields: + - PortId + - Name + - Date + - Time + additional-measurements-name: "Port measurements" + additional-measurements: + - A_Parameter + - B_Parameter + - C_Parameter + - D_Parameter + - E_Parameter diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/zip/nfOamAdapter1.zip b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/zip/nfOamAdapter1.zip new file mode 100644 index 0000000..6ea3cb8 Binary files /dev/null and b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-manager/src/test/resources/zip/nfOamAdapter1.zip differ diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/pom.xml b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/pom.xml new file mode 100644 index 0000000..3dcd893 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/pom.xml @@ -0,0 +1,79 @@ + + + + 4.0.0 + + + org.o-ran-sc.oam + ves-nf-oam-adopter-parent + 1.0.0-SNAPSHOT + ../ves-nf-oam-adopter-parent/pom.xml + + + ves-nf-oam-adopter-pm-sb-rest-client + + + + ${project.groupId} + ves-nf-oam-adopter-pm-manager + + + org.apache.httpcomponents.client5 + httpclient5 + + + com.google.code.gson + gson + + + com.google.guava + guava + + + io.reactivex.rxjava3 + rxjava + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-test + test + + + \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClient.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClient.java new file mode 100644 index 0000000..b1d6008 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClient.java @@ -0,0 +1,157 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.sb.rest.client; + +import static org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.http.DownloadPerformanceManagementFilesHandler.readPerformanceManagementFiles; +import static org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.http.OffSetTimeZoneHandler.readTimeZone; +import static org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.http.TokenHandler.returnToken; +import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import io.reactivex.rxjava3.core.Single; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.zip.ZipInputStream; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequests; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.http.ConnectionClosedException; +import org.apache.hc.core5.http.HttpHeaders; +import org.checkerframework.checker.lock.qual.GuardedBy; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.HttpRestClient; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.PerformanceManagementException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.TokenGenerationException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.ZoneIdException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; +import org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.properties.PmEndpointsUrlsProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public final class DefaultHttpRestClient implements HttpRestClient { + private static final Logger LOG = LoggerFactory.getLogger(DefaultHttpRestClient.class); + + public static final String HTTPS = "https://"; + public static final String BEARER = "Bearer "; + private static final DateTimeFormatter OFFSET_FORMATTER = DateTimeFormatter.ofPattern("xxx"); + private final CloseableHttpAsyncClient client; + @GuardedBy("this") + private final LoadingCache sessionCache = + CacheBuilder.newBuilder().refreshAfterWrite(59, TimeUnit.MINUTES).build(new CacheLoader<>() { + @Override + public String load(final Adapter adapter) throws ExecutionException, InterruptedException { + try { + return returnToken(DefaultHttpRestClient.this.client, DefaultHttpRestClient.this.tokenEndpoint, + adapter); + } catch (final Exception error) { + LOG.error("Failed to read time zone", error); + throw error; + } + } + }); + + @GuardedBy("this") + private final LoadingCache zoneIdCache = + CacheBuilder.newBuilder().build(new CacheLoader<>() { + @Override + public ZoneId load(final Adapter adapter) { + return readTimeZone(DefaultHttpRestClient.this, timeZoneEndpoint, adapter) + .doOnError(error -> LOG.error("Failed to read time zone", error)) + .blockingGet(); + } + }); + private final String pmFilesEndpoint; + private final String timeZoneEndpoint; + private final String tokenEndpoint; + + /** + * Default constructor. + */ + @Autowired + public DefaultHttpRestClient(final CloseableHttpAsyncClient httpAsyncClient, + final PmEndpointsUrlsProperties properties) { + this.client = httpAsyncClient; + this.pmFilesEndpoint = properties.getRanPmEndpoint(); + this.timeZoneEndpoint = properties.getRanTimeZoneOffsetEndpoint(); + this.tokenEndpoint = properties.getRanTokenEndpoint(); + } + + + @Override + public synchronized Single readFiles(final Adapter adapter) { + return readPerformanceManagementFiles(this, pmFilesEndpoint, adapter); + } + + @Override + public Single getTimeZone(final Adapter adapter) { + try { + final ZoneId zoneId = zoneIdCache.get(adapter); + LOG.info("Adapter {} has offset {}", adapter.getHostIpAddress(), + OFFSET_FORMATTER.format(zoneId.getRules().getOffset(Instant.now()))); + return Single.just(zoneId); + } catch (final Exception e) { + final Throwable cause = e.getCause(); + if (cause instanceof PerformanceManagementException) { + return Single.error(cause); + } + return Single.error(new ZoneIdException("Failed to get Zone ID for " + adapter.getHostIpAddress(), cause)); + } + } + + /** + * Execute GET request on adapter endpoint. + * @param adapter destiny + * @param url endpoint + * @return response + */ + public Single get(final Adapter adapter, final String url) { + return getToken(adapter).flatMap(token -> { + final SimpleHttpRequest request = + SimpleHttpRequests.get(HTTPS + adapter.getHostIpAddress() + url); + request.addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_VALUE); + request.addHeader(HttpHeaders.AUTHORIZATION, BEARER + token); + return Single.fromFuture(client.execute(request, null)) + .doOnSubscribe(result -> LOG.trace("GET Request started {} ...", request.toString())) + .doOnSuccess(result -> LOG.trace("GET Request finished {}", request)); + }); + } + + private Single getToken(final Adapter adapter) { + try { + final String token = sessionCache.get(adapter); + return Single.just(token); + } catch (final Exception e) { + if (e.getCause() instanceof TokenGenerationException) { + return Single.error(e.getCause()); + } else if (e.getCause() instanceof ConnectionClosedException) { + return Single.error(e.getCause()); + } + return Single.error(e); + } + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/DownloadPerformanceManagementFilesHandler.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/DownloadPerformanceManagementFilesHandler.java new file mode 100644 index 0000000..77957cb --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/DownloadPerformanceManagementFilesHandler.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.http; + +import io.reactivex.rxjava3.core.Single; +import java.io.ByteArrayInputStream; +import java.util.zip.ZipInputStream; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.hc.client5.http.async.methods.SimpleBody; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.StatusLine; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.PerformanceManagementException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; +import org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.DefaultHttpRestClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class DownloadPerformanceManagementFilesHandler { + + private static final Logger LOG = LoggerFactory.getLogger(DownloadPerformanceManagementFilesHandler.class); + + /** + * Reads and return ZIP CSV PM Files from device. + */ + public static Single readPerformanceManagementFiles(final DefaultHttpRestClient httpSession, + final String pmFilesEndpoint, final Adapter adapter) { + LOG.info("Download PM files from RAN {}", adapter.getHostIpAddress()); + return httpSession.get(adapter, pmFilesEndpoint) + .flatMap(response -> DownloadPerformanceManagementFilesHandler + .validateGetZipFile(adapter, response)) + .map(entity -> new ZipInputStream(new ByteArrayInputStream(entity.getBodyBytes()))); + } + + private static Single validateGetZipFile(final Adapter adapter, final SimpleHttpResponse response) { + final String statusLine = new StatusLine(response).toString(); + final ContentType contentType = response.getContentType(); + final SimpleBody entity = response.getBody(); + if (response.getCode() == HttpStatus.SC_OK && entity != null) { + if (ContentType.APPLICATION_OCTET_STREAM.getMimeType().equals(contentType.getMimeType())) { + return Single.just(entity); + } + } + return Single.error(new PerformanceManagementException( + "Download files from " + adapter.getHostIpAddress() + " failed: " + statusLine)); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/OffSetTimeZoneHandler.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/OffSetTimeZoneHandler.java new file mode 100644 index 0000000..2bf8aeb --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/OffSetTimeZoneHandler.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.http; + +import com.google.gson.Gson; +import io.reactivex.rxjava3.core.Single; +import java.time.ZoneId; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.core5.http.HttpStatus; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.PerformanceManagementEmptyOutputException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.PerformanceManagementException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; +import org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.DefaultHttpRestClient; +import org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.pojos.TimeZoneResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class OffSetTimeZoneHandler { + + private static final Logger LOG = LoggerFactory.getLogger(OffSetTimeZoneHandler.class); + + private static final Gson GSON = new Gson(); + + /** + * Returns time zone of the device. + */ + public static Single readTimeZone(final DefaultHttpRestClient httpRestClient, final String offsetEndpoint, + final Adapter adapter) { + LOG.debug("Read Time Zone from adapter {}", adapter.getHostIpAddress()); + return httpRestClient.get(adapter, offsetEndpoint) + .map(response -> validateGet(response, adapter)) + .map(ZoneId::of); + } + + private static String validateGet(final SimpleHttpResponse response, final Adapter adapter) { + if (response.getCode() != HttpStatus.SC_OK) { + throw new PerformanceManagementException( + "Get Zone offset failed for " + adapter.getHostIpAddress() + " Code: " + response.getCode()); + } + final String output = response.getBody().getBodyText(); + if (output.isEmpty()) { + throw new PerformanceManagementEmptyOutputException( + "Get Zone offset failed for " + adapter.getHostIpAddress() + " . Empty output received"); + } + return GSON.fromJson(output, TimeZoneResponse.class).getOffset(); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/TokenHandler.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/TokenHandler.java new file mode 100644 index 0000000..26c62b5 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/http/TokenHandler.java @@ -0,0 +1,53 @@ +package org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.http; + +import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE; + +import com.google.gson.Gson; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.concurrent.ExecutionException; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequests; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.StatusLine; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.exceptions.TokenGenerationException; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; +import org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.pojos.TokenResponse; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class TokenHandler { + + public static final Gson GSON = new Gson(); + public static final String HTTPS = "https://"; + + /** + * Request Token under defined endpoint. + */ + public static synchronized String returnToken(final CloseableHttpAsyncClient client, final String tokenEndpoint, + final Adapter adapter) throws ExecutionException, InterruptedException { + final String host = HTTPS + adapter.getHostIpAddress(); + final SimpleHttpRequest request = SimpleHttpRequests.post(host + tokenEndpoint); + final String basicAuth = Base64.getEncoder().encodeToString( + (adapter.getUsername() + ":" + adapter.getPassword()).getBytes(StandardCharsets.UTF_8)); + request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); + request.addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_VALUE); + request.addHeader(HttpHeaders.ACCEPT, APPLICATION_JSON_VALUE); + + final SimpleHttpResponse response = client.execute(request, null).get(); + final String statusLine = new StatusLine(response).toString(); + if (response.getCode() != HttpStatus.SC_OK) { + throw new TokenGenerationException("Failed to obtain a token for host " + host + ": " + statusLine); + } + final String output = response.getBody().getBodyText(); + if (output.isEmpty()) { + throw new TokenGenerationException( + "Failed to obtain a token for host " + host + ", empty output: " + statusLine); + } + return GSON.fromJson(output, TokenResponse.class).getToken(); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/pojos/TimeZoneResponse.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/pojos/TimeZoneResponse.java new file mode 100644 index 0000000..853951d --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/pojos/TimeZoneResponse.java @@ -0,0 +1,34 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.pojos; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@RequiredArgsConstructor +@Getter +@Setter +public class TimeZoneResponse { + @SerializedName(value = "offset") + private @NonNull final String offset; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/pojos/TokenResponse.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/pojos/TokenResponse.java new file mode 100644 index 0000000..195922f --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/pojos/TokenResponse.java @@ -0,0 +1,29 @@ +/* + * ============LICENSE_START======================================================= + * O-RAN-SC + * ================================================================================ + * Copyright © 2021 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.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.pojos; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class TokenResponse { + private String token; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/properties/PmEndpointsUrlsProperties.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/properties/PmEndpointsUrlsProperties.java new file mode 100644 index 0000000..65a6826 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/main/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/properties/PmEndpointsUrlsProperties.java @@ -0,0 +1,23 @@ +package org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.properties; + +import javax.validation.constraints.NotEmpty; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.validation.annotation.Validated; + +@Component +@ConfigurationProperties(prefix = "pm-rest-manager") +@Data +@NoArgsConstructor +@Validated +public class PmEndpointsUrlsProperties { + + @NotEmpty + private String ranTokenEndpoint; + @NotEmpty + private String ranPmEndpoint; + @NotEmpty + private String ranTimeZoneOffsetEndpoint; +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClientTest.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClientTest.java new file mode 100644 index 0000000..f9c115a --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/DefaultHttpRestClientTest.java @@ -0,0 +1,180 @@ +package org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.when; + +import io.reactivex.rxjava3.observers.TestObserver; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.zip.ZipInputStream; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.concurrent.FutureCallback; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.mockito.stubbing.Answer; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.api.HttpRestClient; +import org.o.ran.oam.nf.oam.adopter.pm.rest.manager.pojos.Adapter; +import org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client.properties.PmEndpointsUrlsProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.MethodMode; + +@SpringBootTest(classes = {DefaultHttpRestClient.class, PmEndpointsUrlsProperties.class}) +@EnableConfigurationProperties +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class DefaultHttpRestClientTest { + + private static final Adapter ADAPTER = + Adapter.builder().hostIpAddress("150.62.25.26").username("admin").password("secretPassword").build(); + @Autowired + public HttpRestClient restClient; + + @MockBean + CloseableHttpAsyncClient client; + + @Test + @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD) + public void testGetFailedToken() { + final SimpleHttpResponse response = + SimpleHttpResponse.create(HttpStatus.SC_UNAUTHORIZED, "error", ContentType.APPLICATION_JSON); + + when(client.execute(any(SimpleHttpRequest.class), nullable(FutureCallback.class))) + .thenAnswer((Answer>) invocation -> { + final SimpleHttpRequest req = (SimpleHttpRequest) invocation.getArguments()[0]; + if ("/auth/token".equals(req.getPath())) { + return CompletableFuture.completedFuture(response); + } + throw new IllegalStateException("Unexpected value: " + req.getPath()); + }); + + + final TestObserver observer = restClient.getTimeZone(ADAPTER).test(); + observer.assertError(throwable -> throwable.getMessage() + .equals("Failed to obtain a token for host https://150.62.25.26: HTTP/1.1 401 Unauthorized")); + } + + @Test + public void testReadFiles() throws IOException { + final String tokenJson = JsonUtils.readJson("/json/tokenResponse.json"); + final SimpleHttpResponse response = + SimpleHttpResponse.create(HttpStatus.SC_OK, tokenJson, ContentType.APPLICATION_JSON); + + final SimpleHttpResponse zipResponse = + SimpleHttpResponse.create(HttpStatus.SC_OK, "mockZip", ContentType.APPLICATION_OCTET_STREAM); + + when(client.execute(any(SimpleHttpRequest.class), nullable(FutureCallback.class))) + .thenAnswer((Answer>) invocation -> { + final SimpleHttpRequest req = (SimpleHttpRequest) invocation.getArguments()[0]; + switch (req.getPath()) { + case "/auth/token": + return CompletableFuture.completedFuture(response); + case "/pm/files": + return CompletableFuture.completedFuture(zipResponse); + default: + throw new IllegalStateException("Unexpected value: " + req.getPath()); + } + }); + + + final TestObserver observer = restClient.readFiles(ADAPTER).test(); + final ZipInputStream expected = new ZipInputStream(new ByteArrayInputStream("mockZip".getBytes())); + observer.assertValue(zip -> Arrays.equals(zip.readAllBytes(), expected.readAllBytes())); + } + + @Test + public void testReadFilesResponseFail() throws IOException { + final String tokenJson = JsonUtils.readJson("/json/tokenResponse.json"); + final SimpleHttpResponse response = + SimpleHttpResponse.create(HttpStatus.SC_OK, tokenJson, ContentType.APPLICATION_JSON); + + final SimpleHttpResponse zipResponse = SimpleHttpResponse.create(HttpStatus.SC_BAD_REQUEST, "mockZip", + ContentType.APPLICATION_OCTET_STREAM); + + when(client.execute(any(SimpleHttpRequest.class), nullable(FutureCallback.class))) + .thenAnswer((Answer>) invocation -> { + final SimpleHttpRequest req = (SimpleHttpRequest) invocation.getArguments()[0]; + switch (req.getPath()) { + case "/auth/token": + return CompletableFuture.completedFuture(response); + case "/pm/files": + return CompletableFuture.completedFuture(zipResponse); + default: + throw new IllegalStateException("Unexpected value: " + req.getPath()); + } + }); + + + final TestObserver observer = restClient.readFiles(ADAPTER).test(); + observer.assertError(throwable -> throwable.getMessage() + .equals("Download files from 150.62.25.26 failed: HTTP/1.1 400 Bad Request")); + } + + @Test + public void testGetTimeOffset() throws IOException { + final String tokenJson = JsonUtils.readJson("/json/tokenResponse.json"); + final SimpleHttpResponse response = + SimpleHttpResponse.create(HttpStatus.SC_OK, tokenJson, ContentType.APPLICATION_JSON); + + final String timeZoneOFfsetResponseJson = JsonUtils.readJson("/json/timeZoneOffsetResponse.json"); + final SimpleHttpResponse timeOffsetResponse = + SimpleHttpResponse.create(HttpStatus.SC_OK, timeZoneOFfsetResponseJson, ContentType.APPLICATION_JSON); + + when(client.execute(any(SimpleHttpRequest.class), nullable(FutureCallback.class))) + .thenAnswer((Answer>) invocation -> { + final SimpleHttpRequest req = (SimpleHttpRequest) invocation.getArguments()[0]; + switch (req.getPath()) { + case "/auth/token": + return CompletableFuture.completedFuture(response); + case "/system/timeZone": + return CompletableFuture.completedFuture(timeOffsetResponse); + default: + throw new IllegalStateException("Unexpected value: " + req.getPath()); + } + }); + + + final TestObserver observer = restClient.getTimeZone(ADAPTER).test(); + observer.assertValues(ZoneId.of("+02:00")); + } + + @Test + public void testGetTimeOffsetFail() throws IOException { + final String tokenJson = JsonUtils.readJson("/json/tokenResponse.json"); + final SimpleHttpResponse response = + SimpleHttpResponse.create(HttpStatus.SC_OK, tokenJson, ContentType.APPLICATION_JSON); + + final SimpleHttpResponse timeOffsetResponse = + SimpleHttpResponse.create(HttpStatus.SC_OK, "", ContentType.APPLICATION_JSON); + + when(client.execute(any(SimpleHttpRequest.class), nullable(FutureCallback.class))) + .thenAnswer((Answer>) invocation -> { + final SimpleHttpRequest req = (SimpleHttpRequest) invocation.getArguments()[0]; + switch (req.getPath()) { + case "/auth/token": + return CompletableFuture.completedFuture(response); + case "/system/timeZone": + return CompletableFuture.completedFuture(timeOffsetResponse); + default: + throw new IllegalStateException("Unexpected value: " + req.getPath()); + } + }); + + + final TestObserver observer = restClient.getTimeZone(ADAPTER).test(); + observer.assertError(throwable -> throwable.getMessage() + .equals("Get Zone offset failed for 150.62.25.26 . Empty output received")); + } +} \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/JsonUtils.java b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/JsonUtils.java new file mode 100644 index 0000000..60bf0ef --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/java/org/o/ran/oam/nf/oam/adopter/pm/sb/rest/client/JsonUtils.java @@ -0,0 +1,13 @@ +package org.o.ran.oam.nf.oam.adopter.pm.sb.rest.client; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import lombok.experimental.UtilityClass; +import org.apache.commons.io.IOUtils; + +@UtilityClass +final class JsonUtils { + static String readJson(final String url) throws IOException { + return IOUtils.toString(JsonUtils.class.getResourceAsStream(url), StandardCharsets.UTF_8); + } +} diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/application.yaml b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/application.yaml new file mode 100644 index 0000000..f81c8ff --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/application.yaml @@ -0,0 +1,4 @@ +pm-rest-manager: + ran-token-endpoint: /auth/token + ran-pm-endpoint: /pm/files + ran-time-zone-offset-endpoint: /system/timeZone \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/json/timeZoneOffsetResponse.json b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/json/timeZoneOffsetResponse.json new file mode 100644 index 0000000..c80769c --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/json/timeZoneOffsetResponse.json @@ -0,0 +1,3 @@ +{ + "offset": "+02:00" +} \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/json/tokenResponse.json b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/json/tokenResponse.json new file mode 100644 index 0000000..2269aa0 --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/json/tokenResponse.json @@ -0,0 +1,3 @@ +{ + "token": "someRandomToken" +} \ No newline at end of file diff --git a/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000..ca6ee9c --- /dev/null +++ b/ves-nf-oam-adopter/ves-nf-oam-adopter-pm-sb-rest-client/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file