From 83f8646f702f9cffbd25d8124476465ee8f94af0 Mon Sep 17 00:00:00 2001 From: Shalini Shivam Date: Fri, 13 Dec 2024 15:56:10 +0100 Subject: [PATCH] Support Output response to OPA query Description : For details refer https://lf-onap.atlassian.net/wiki/spaces/DW/pages/51150925/OPA+PDP Issue-ID: POLICY-5204 Change-Id: Id6d51fa83957fb560afec2d85cc0d45d6dda6900 Signed-off-by: Shalini Shivam --- Dockerfile | 18 +++ api/openapi.yaml | 23 ++- api/register-handlers.go | 3 +- api/register-handlers_test.go | 3 +- build/Dockerfile | 19 +++ build_image.sh | 5 +- cfg/config.go | 43 ++++- cfg/config_test.go | 59 ++++++- cmd/opa-pdp/opa-pdp.go | 47 ++++-- cmd/opa-pdp/opa-pdp_test.go | 13 +- consts/constants.go | 28 ++-- pkg/bundleserver/bundle-server.go | 1 + pkg/bundleserver/bundle-server_test.go | 3 +- pkg/decision/decision-provider.go | 144 +++++++++++++++-- pkg/decision/decision-provider_test.go | 177 ++++++++++++++++++++- pkg/healthcheck/healthcheck.go | 3 +- pkg/healthcheck/healthcheck_test.go | 109 ++++++++++++- pkg/kafkacomm/handler/pdp_message_handler.go | 99 ++++++++---- pkg/kafkacomm/handler/pdp_message_handler_test.go | 61 ++++++- pkg/kafkacomm/handler/pdp_state_change_handler.go | 3 +- .../handler/pdp_state_change_handler_test.go | 3 +- .../handler/pdp_update_message_handler.go | 3 +- .../handler/pdp_update_message_handler_test.go | 10 +- pkg/kafkacomm/pdp_topic_consumer.go | 120 +++++++++----- pkg/kafkacomm/pdp_topic_consumer_test.go | 3 +- pkg/kafkacomm/pdp_topic_producer.go | 5 +- pkg/kafkacomm/pdp_topic_producer_test.go | 3 +- pkg/kafkacomm/publisher/pdp-heartbeat.go | 5 +- pkg/kafkacomm/publisher/pdp-heartbeat_test.go | 3 +- pkg/kafkacomm/publisher/pdp-pap-registration.go | 3 +- .../publisher/pdp-pap-registration_test.go | 3 +- pkg/kafkacomm/publisher/pdp-status-publisher.go | 3 +- .../publisher/pdp-status-publisher_test.go | 3 +- pkg/log/log.go | 3 +- pkg/log/log_test.go | 3 +- pkg/metrics/counters.go | 53 +++++- pkg/metrics/counters_test.go | 19 +++ pkg/metrics/statistics-provider.go | 21 +++ pkg/metrics/statistics-provider_test.go | 19 +++ pkg/model/healthcheckmessage.go | 17 +- pkg/model/mesages.go | 49 +++--- pkg/model/messages_test.go | 3 +- pkg/model/oapicodegen/models.go | 7 +- pkg/model/pdphealthstatus.go | 3 +- pkg/model/pdphealthstatus_test.go | 3 +- pkg/model/pdpresponsedetails.go | 3 +- pkg/model/pdpresponsedetails_test.go | 3 +- pkg/model/pdpstate.go | 3 +- pkg/model/pdpstate_test.go | 3 +- pkg/model/toscaconceptidentifier.go | 3 +- pkg/model/toscaconceptidentifier_test.go | 3 +- pkg/opasdk/opasdk.go | 3 +- pkg/opasdk/opasdk_test.go | 3 +- pkg/pdpattributes/pdpattributes.go | 3 +- pkg/pdpattributes/pdpattributes_test.go | 3 +- pkg/pdpstate/pdpstate.go | 3 +- pkg/pdpstate/pdpstate_test.go | 3 +- pkg/utils/utils.go | 3 +- pkg/utils/utils_test.go | 3 +- test/README.md | 38 +++++ test/data/abac/data.json | 94 +++++++++++ test/data/account/data.json | 16 ++ test/data/action/data.json | 43 +++++ test/data/organization/data.json | 32 ++++ test/data/role/data.json | 63 ++++++++ test/docker-compose.yml | 6 +- version | 2 +- 67 files changed, 1348 insertions(+), 216 deletions(-) create mode 100644 test/data/abac/data.json create mode 100644 test/data/account/data.json create mode 100644 test/data/action/data.json create mode 100644 test/data/organization/data.json create mode 100644 test/data/role/data.json diff --git a/Dockerfile b/Dockerfile index 389c328..ecd5c49 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,21 @@ +# - +# ========================LICENSE_START================================= +# Copyright (C) 2024: Deutsche Telekom +# +# 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=================================== +# FROM curlimages/curl:7.78.0 AS build # Get OPA diff --git a/api/openapi.yaml b/api/openapi.yaml index aaff2b9..a9b8191 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1,6 +1,6 @@ # # ========================LICENSE_START================================= -# Copyright (C) 2024: Deutsche Telecom +# Copyright (C) 2024: Deutsche Telekom # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,13 +13,14 @@ # 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: "Policy OPA PDP Documentation" description: Policy OPA PDP Service - version: 1.0.0 + version: 1.0.2 x-component: Policy Framework x-planned-retirement-date: tbd contact: @@ -175,7 +176,7 @@ paths: tags: - Statistics summary: Fetch current statistics - description: Provides current statistics of the Policy OPA PDP component + description: Provides current statistics of the Policy OPA PDP component operationId: statistics parameters: - name: X-ONAP-RequestID @@ -296,6 +297,10 @@ components: description: "Time offset in hours and minutes, e.g., '+02:00' or '-05:00'" policyName: type: string + policyFilter: + type: array + items: + type: string input: type: object additionalProperties: true @@ -329,8 +334,12 @@ components: - PERMIT - DENY - INDETERMINATE + - NOTAPPLICABLE policyName: type: string + output: + type: object + additionalProperties: true StatisticsReport: type: object properties: @@ -367,8 +376,14 @@ components: indeterminantDecisionsCount: type: integer format: int64 + querySuccessCount: + type: integer + format: int64 + queryFailureCount: + type: integer + format: int64 securitySchemes: basicAuth: type: http description: "" - scheme: basic \ No newline at end of file + scheme: basic diff --git a/api/register-handlers.go b/api/register-handlers.go index 37028d2..4b21314 100644 --- a/api/register-handlers.go +++ b/api/register-handlers.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package api provides HTTP handlers for the policy-opa-pdp service. diff --git a/api/register-handlers_test.go b/api/register-handlers_test.go index 72624f8..801cb0e 100644 --- a/api/register-handlers_test.go +++ b/api/register-handlers_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/build/Dockerfile b/build/Dockerfile index 2905d77..84359c3 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,3 +1,22 @@ +# - +# ========================LICENSE_START================================= +# Copyright (C) 2024: Deutsche Telekom +# +# 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=================================== +# + FROM curlimages/curl:7.78.0 AS build # Get OPA diff --git a/build_image.sh b/build_image.sh index fb3b19b..6141f5f 100755 --- a/build_image.sh +++ b/build_image.sh @@ -1,7 +1,7 @@ #!/bin/bash # - # ========================LICENSE_START================================= -# Copyright (C) 2024: Deutsche Telecom +# Copyright (C) 2024: Deutsche Telekom # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,8 +14,9 @@ # 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=================================== -# + export IMAGE_NAME="nexus3.onap.org:10003/onap/policy-opa-pdp" VERSION_FILE="version" diff --git a/cfg/config.go b/cfg/config.go index 4840688..ef046de 100644 --- a/cfg/config.go +++ b/cfg/config.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package cfg provides configuration settings for the policy-opa-pdp service. @@ -22,8 +23,10 @@ package cfg import ( + "fmt" log "github.com/sirupsen/logrus" "os" + "regexp" "strconv" ) @@ -46,6 +49,7 @@ var ( UseSASLForKAFKA string KAFKA_USERNAME string KAFKA_PASSWORD string + JAASLOGIN string ) // Initializes the configuration settings. @@ -65,8 +69,10 @@ func init() { Username = getEnv("API_USER", "policyadmin") Password = getEnv("API_PASSWORD", "zb!XztG34") UseSASLForKAFKA = getEnv("UseSASLForKAFKA", "false") - KAFKA_USERNAME = getEnv("KAFKA_USERNAME", "strimzi-kafka-user") - KAFKA_PASSWORD = getEnv("KAFKA_PASSWORD", "kafkaSecretPassword123") + KAFKA_USERNAME, KAFKA_PASSWORD = getSaslJAASLOGINFromEnv(JAASLOGIN) + log.Debugf("Username: %s", KAFKA_USERNAME) + log.Debugf("Password: %s", KAFKA_PASSWORD) + log.Debug("Configuration module: environment initialised") } @@ -101,3 +107,34 @@ func getLogLevel(key string, defaultVal string) log.Level { return log.DebugLevel } } + +func getSaslJAASLOGINFromEnv(JAASLOGIN string) (string, string) { + // Retrieve the value of the environment variable + decodingConfigBytes := getEnv("JAASLOGIN", "JAASLOGIN") + if decodingConfigBytes == "" { + return "", "" + } + + decodedConfig := string(decodingConfigBytes) + fmt.Println("decodedConfig", decodedConfig) + + // Extract username and password using regex + usernamePattern := `username=["'](.+?)["']` + passwordPattern := `password=["'](.+?)["']` + + // Extract username + usernameMatch := regexp.MustCompile(usernamePattern).FindStringSubmatch(decodedConfig) + if len(usernameMatch) < 2 { + return "", "" + } + username := usernameMatch[1] + + // Extract password + passwordMatch := regexp.MustCompile(passwordPattern).FindStringSubmatch(decodedConfig) + if len(passwordMatch) < 2 { + return "", "" + } + password := passwordMatch[1] + + return username, password +} diff --git a/cfg/config_test.go b/cfg/config_test.go index fe91804..092a67e 100644 --- a/cfg/config_test.go +++ b/cfg/config_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // @@ -20,6 +21,7 @@ package cfg import ( log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" "os" "testing" ) @@ -74,3 +76,58 @@ func TestGetLogLevel(t *testing.T) { t.Errorf("Expected %v, got %v", log.InfoLevel, val) } } + +func TestGetSaslJAASLOGINFromEnv(t *testing.T) { + // Define mock JAASLOGIN value + mockJAASLOGIN := `username="mockUser" password="mockPassword"` + + // Set the mock environment variable + os.Setenv("JAASLOGIN", mockJAASLOGIN) + defer os.Unsetenv("JAASLOGIN") // Ensure the environment variable is unset after the test + + // Call the function + username, password := getSaslJAASLOGINFromEnv("JAASLOGIN") + + // Validate the result + assert.Equal(t, "mockUser", username, "Expected username to match mock value") + assert.Equal(t, "mockPassword", password, "Expected password to match mock value") +} + +func TestGetSaslJAASLOGINFromEnv_InvalidEnv(t *testing.T) { + // Set the mock environment variable with an invalid format + mockJAASLOGIN := `username="mockUser" password=mockPassword` + os.Setenv("JAASLOGIN", mockJAASLOGIN) + defer os.Unsetenv("JAASLOGIN") // Ensure the environment variable is unset after the test + + // Call the function + username, password := getSaslJAASLOGINFromEnv("JAASLOGIN") + + // Validate that the function returns empty strings for invalid input + assert.Empty(t, username, "Expected username to be empty for invalid format") + assert.Empty(t, password, "Expected password to be empty for invalid format") +} + +func TestGetSaslJAASLOGINFromEnv_EmptyEnv(t *testing.T) { + // Set an empty environment variable + os.Setenv("JAASLOGIN", "") + defer os.Unsetenv("JAASLOGIN") // Ensure the environment variable is unset after the test + + // Call the function + username, password := getSaslJAASLOGINFromEnv("JAASLOGIN") + + // Validate that the function returns empty strings for an empty value + assert.Empty(t, username, "Expected username to be empty for empty environment variable") + assert.Empty(t, password, "Expected password to be empty for empty environment variable") +} + +func TestGetSaslJAASLOGINFromEnv_MissingEnv(t *testing.T) { + // Unset the environment variable to simulate missing variable + os.Unsetenv("JAASLOGIN") + + // Call the function + username, password := getSaslJAASLOGINFromEnv("JAASLOGIN") + + // Validate that the function returns empty strings for a missing environment variable + assert.Empty(t, username, "Expected username to be empty for missing environment variable") + assert.Empty(t, password, "Expected password to be empty for missing environment variable") +} diff --git a/cmd/opa-pdp/opa-pdp.go b/cmd/opa-pdp/opa-pdp.go index 0def78f..f2b2e0b 100644 --- a/cmd/opa-pdp/opa-pdp.go +++ b/cmd/opa-pdp/opa-pdp.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package main is the entry point for the policy-opa-pdp service. @@ -62,6 +63,9 @@ var ( func main() { log.Debugf("Starting OPA PDP Service") + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + // Initialize Handlers and Build Bundle initializeHandlersFunc() if err := initializeBundleFunc(exec.Command); err != nil { @@ -85,7 +89,7 @@ func main() { // Start Kafka Consumer and producer kc, producer, err := startKafkaConsAndProdFunc() - if err != nil { + if err != nil || kc == nil { log.Warnf("Kafka consumer initialization failed: %v", err) } defer producer.Close() @@ -97,19 +101,24 @@ func main() { return } - // start pdp message handler in a seperate routine - handleMessagesFunc(kc, sender) + handleMessagesFunc(ctx, kc, sender) // Handle OS Interrupts and Graceful Shutdown interruptChannel := make(chan os.Signal, 1) signal.Notify(interruptChannel, os.Interrupt, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP) - handleShutdownFunc(kc, interruptChannel) + handleShutdownFunc(kc, interruptChannel, cancel) } // starts pdpMessage Handler in a seperate routine which handles incoming messages on Kfka topic -func handleMessages(kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) { - go handler.PdpMessageHandler(kc, topic, sender) +func handleMessages(ctx context.Context, kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) { + + go func() { + err := handler.PdpMessageHandler(ctx, kc, topic, sender) + if err != nil { + log.Warnf("Erro in PdpUpdate Message Handler: %v", err) + } + }() } // register pdp with PAP @@ -180,7 +189,7 @@ func startKafkaConsAndProd() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer return kc, producer, nil } -func handleShutdown(kc *kafkacomm.KafkaConsumer, interruptChannel chan os.Signal) { +func handleShutdown(kc *kafkacomm.KafkaConsumer, interruptChannel chan os.Signal, cancel context.CancelFunc) { myLoop: for { @@ -190,15 +199,27 @@ myLoop: break myLoop } } - + cancel() + log.Debugf("Loop Exited and shutdown started") signal.Stop(interruptChannel) - if kc != nil { - kc.Consumer.Unsubscribe() - kc.Consumer.Close() - log.Debug("Consumer Unsubscribed and Closed......") + if kc == nil { + log.Debugf("kc is nil so skipping") + return + } + + if err := kc.Consumer.Unsubscribe(); err != nil { + log.Warnf("Failed to unsubscribe consumer: %v", err) + } else { + log.Debugf("Consumer Unsubscribed....") + } + if err := kc.Consumer.Close(); err != nil { + log.Debug("Failed to close consumer......") + } else { + log.Debugf("Consumer closed....") } + handler.SetShutdownFlag() publisher.StopTicker() time.Sleep(time.Duration(consts.SHUTDOWN_WAIT_TIME) * time.Second) diff --git a/cmd/opa-pdp/opa-pdp_test.go b/cmd/opa-pdp/opa-pdp_test.go index 9da4c41..9683362 100644 --- a/cmd/opa-pdp/opa-pdp_test.go +++ b/cmd/opa-pdp/opa-pdp_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // @@ -76,15 +77,16 @@ func TestHandleShutdown(t *testing.T) { Consumer: mockConsumer, } interruptChannel := make(chan os.Signal, 1) + _, cancel := context.WithCancel(context.Background()) + defer cancel() go func() { time.Sleep(500 * time.Millisecond) interruptChannel <- os.Interrupt }() - done := make(chan bool) go func() { - handleShutdown(mockKafkaConsumer, interruptChannel) + handleShutdown(mockKafkaConsumer, interruptChannel, cancel) done <- true }() @@ -145,14 +147,15 @@ func TestMainFunction(t *testing.T) { return false // Simulate successful registration } - handleMessagesFunc = func(kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) { + handleMessagesFunc = func(ctx context.Context, kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) { return } // Mock handleShutdown interruptChannel := make(chan os.Signal, 1) - handleShutdownFunc = func(kc *kafkacomm.KafkaConsumer, interruptChan chan os.Signal) { + handleShutdownFunc = func(kc *kafkacomm.KafkaConsumer, interruptChan chan os.Signal, cancel context.CancelFunc) { interruptChannel <- os.Interrupt + cancel() } // Run main function in a goroutine diff --git a/consts/constants.go b/consts/constants.go index 601608f..d800e0d 100644 --- a/consts/constants.go +++ b/consts/constants.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package consts provides constant values used throughout the policy-opa-pdp service. @@ -47,18 +48,19 @@ package consts // OkCode - The Code for HealthCheck response // HealthCheckMessage - The Healtcheck Message var ( - LogFilePath = "/var/logs/logs.log" - LogMaxSize = 10 - LogMaxBackups = 3 - OpasdkConfigPath = "/app/config/config.json" - Opa = "/app/opa" - BuildBundle = "build" - Policies = "/app/policies" - Data = "/app/policies/data" - Output = "-o" - BundleTarGz = "bundle.tar.gz" - BundleTarGzFile = "/app/bundles/bundle.tar.gz" - PdpGroup = "defaultGroup" + LogFilePath = "/var/logs/logs.log" + LogMaxSize = 10 + LogMaxBackups = 3 + OpasdkConfigPath = "/app/config/config.json" + Opa = "/app/opa" + BuildBundle = "build" + Policies = "/opt/policies" + Data = "/opt/data" + Output = "-o" + BundleTarGz = "bundle.tar.gz" + BundleTarGzFile = "/app/bundles/bundle.tar.gz" + PdpGroup = "opaGroup" + //This is a workaround as currently opa-pdp is not defined in the PapDB defaultGroup configuration and creating it manually overrides the existing configuration, so currently PdpGroup is opaGroup and it will be changed to defaultGroup once added in the configuration. PdpType = "opa" ServerPort = ":8282" SERVER_WAIT_UP_TIME = 5 diff --git a/pkg/bundleserver/bundle-server.go b/pkg/bundleserver/bundle-server.go index fe48de0..726a4be 100644 --- a/pkg/bundleserver/bundle-server.go +++ b/pkg/bundleserver/bundle-server.go @@ -13,6 +13,7 @@ // 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=================================== // Package bundleserver provides functionalities for serving and building OPA bundles. diff --git a/pkg/bundleserver/bundle-server_test.go b/pkg/bundleserver/bundle-server_test.go index eda22b5..676b4db 100644 --- a/pkg/bundleserver/bundle-server_test.go +++ b/pkg/bundleserver/bundle-server_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/decision/decision-provider.go b/pkg/decision/decision-provider.go index 374aabf..48d6edf 100644 --- a/pkg/decision/decision-provider.go +++ b/pkg/decision/decision-provider.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package decision provides functionalities for handling decision requests using OPA (Open Policy Agent). @@ -33,7 +34,7 @@ import ( "policy-opa-pdp/pkg/pdpstate" "policy-opa-pdp/pkg/utils" "strings" - + "fmt" "github.com/google/uuid" openapi_types "github.com/oapi-codegen/runtime/types" "github.com/open-policy-agent/opa/sdk" @@ -73,11 +74,12 @@ func writeErrorJSONResponse(res http.ResponseWriter, status int, errorDescriptio } // creates a decision response based on the provided parameters -func createSuccessDecisionResponse(statusMessage, decision, policyName string) *oapicodegen.OPADecisionResponse { +func createSuccessDecisionResponse(statusMessage, decision, policyName string, output map[string]interface{}) *oapicodegen.OPADecisionResponse { return &oapicodegen.OPADecisionResponse{ StatusMessage: &statusMessage, Decision: (*oapicodegen.OPADecisionResponseDecision)(&decision), PolicyName: &policyName, + Output: &output, } } @@ -181,12 +183,21 @@ func OpaDecision(res http.ResponseWriter, req *http.Request) { log.Debugf("SDK making a decision") options := sdk.DecisionOptions{Path: *decisionReq.PolicyName, Input: decisionReq.Input} + decision, err := opa.Decision(ctx, options) + jsonOutput, err := json.MarshalIndent(decision, "", " ") + if err != nil { + log.Warnf("Error serializing decision output: %v\n", err) + return + } + log.Debugf("RAW opa Decision output:\n%s\n", string(jsonOutput)) + // Check for errors in the OPA decision if err != nil { if strings.Contains(err.Error(), "opa_undefined_error") { - decisionRes := createSuccessDecisionResponse(err.Error(), string(oapicodegen.INDETERMINATE), *decisionReq.PolicyName) + decisionRes := createSuccessDecisionResponse(err.Error(), string(oapicodegen.INDETERMINATE), + *decisionReq.PolicyName, nil) writeOpaJSONResponse(res, http.StatusOK, *decisionRes) metrics.IncrementIndeterminantDecisionsCount() return @@ -199,15 +210,128 @@ func OpaDecision(res http.ResponseWriter, req *http.Request) { } } - // Check the decision result - if decisionExcult, ok := decision.Result.(bool); !ok || !decisionExcult { - decisionRes := createSuccessDecisionResponse("OPA Denied", string(oapicodegen.DENY), *decisionReq.PolicyName) + var policyFilter []string + if decisionReq.PolicyFilter != nil { + policyFilter = *decisionReq.PolicyFilter + } + + // Decision Result Processing + outputMap := make(map[string]interface{}) + // Check if the decision result is a bool or a map + switch result := decision.Result.(type) { + case bool: + // If the result is a boolean (true/false) + if result { + // If "allow" is true, process filters if they exist + if len(policyFilter) > 0 { + // If filters are present, we apply them + decisionRes := createSuccessDecisionResponse("OPA Allowed", string(oapicodegen.PERMIT), *decisionReq.PolicyName, nil) + metrics.IncrementPermitDecisionsCount() + writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + return + } + + // No filters provided, just allow the decision + decisionRes := createSuccessDecisionResponse("OPA Allowed", string(oapicodegen.PERMIT), *decisionReq.PolicyName, nil) + metrics.IncrementPermitDecisionsCount() + writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + return + } + + // If "allow" is false + decisionRes := createSuccessDecisionResponse("OPA Denied", string(oapicodegen.DENY), *decisionReq.PolicyName, nil) metrics.IncrementDenyDecisionsCount() writeOpaJSONResponse(res, http.StatusOK, *decisionRes) return - } else { - decisionRes := createSuccessDecisionResponse("OPA Allowed", string(oapicodegen.PERMIT), *decisionReq.PolicyName) - metrics.IncrementPermitDecisionsCount() + + case map[string]interface{}: + if len(policyFilter) > 0 { + // Apply the policy filter if present + filteredResult := applyPolicyFilter(result, policyFilter) + if filteredResultMap, ok := filteredResult.(map[string]interface{}); ok && len(filteredResultMap) > 0 { + outputMap = filteredResultMap + } else { + decisionRes := createSuccessDecisionResponse( + "No Decision: Result is Empty after applying filter", + string(oapicodegen.NOTAPPLICABLE), + *decisionReq.PolicyName, nil) + metrics.IncrementQueryFailureCount() + writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + return + } + } else { + // Process result without filters + var statusMessage string + boolValueFound := false + for key, value := range result { + if len(statusMessage) == 0 { + statusMessage = fmt.Sprintf("%s: %v", key, value) + } else { + statusMessage = fmt.Sprintf("%s ,%s: %v", statusMessage, key, value) + } + if boolVal, ok := value.(bool); ok { + boolValueFound = boolVal + } + } + // Return decision based on boolean value + if boolValueFound { + decisionRes := createSuccessDecisionResponse(statusMessage, string(oapicodegen.PERMIT), + *decisionReq.PolicyName, nil) + metrics.IncrementPermitDecisionsCount() + writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + return + } else { + decisionRes := createSuccessDecisionResponse(statusMessage, string(oapicodegen.DENY), + *decisionReq.PolicyName, nil) + metrics.IncrementDenyDecisionsCount() + writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + return + } + + } + + // If only non-boolean values were collected + if len(outputMap) > 0 { + decisionRes := createSuccessDecisionResponse( + "Decision Not Applicable, Output Only", + string(oapicodegen.NOTAPPLICABLE), + *decisionReq.PolicyName, outputMap) + metrics.IncrementQuerySuccessCount() + writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + } else { + decisionRes := createSuccessDecisionResponse( + "No Decision: Result is Empty", + string(oapicodegen.NOTAPPLICABLE), + *decisionReq.PolicyName, nil) + metrics.IncrementQueryFailureCount() + writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + } + return + + default: + // Handle unexpected types in decision.Result + decisionRes := createSuccessDecisionResponse("Invalid decision result format", string(oapicodegen.DENY), *decisionReq.PolicyName, nil) + metrics.IncrementDenyDecisionsCount() writeOpaJSONResponse(res, http.StatusOK, *decisionRes) + return + } + +} + +// Function to apply policy filter to decision result +func applyPolicyFilter(result map[string]interface{}, filters []string) interface{} { + + // Assuming filter matches specific keys or values + filteredOutput := make(map[string]interface{}) + for key, value := range result { + for _, filter := range filters { + if strings.Contains(key, filter) { + filteredOutput[key] = value + break + } + + } } + + return filteredOutput } diff --git a/pkg/decision/decision-provider_test.go b/pkg/decision/decision-provider_test.go index c8a1bf6..f05739c 100644 --- a/pkg/decision/decision-provider_test.go +++ b/pkg/decision/decision-provider_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // @@ -26,6 +27,7 @@ import ( "os" "policy-opa-pdp/consts" "policy-opa-pdp/pkg/model" + "policy-opa-pdp/pkg/model/oapicodegen" "policy-opa-pdp/pkg/pdpstate" "testing" @@ -133,3 +135,176 @@ func TestOpaDecision_PassiveState(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, rec.Code) assert.Contains(t, rec.Body.String(), " System Is In PASSIVE State") } + +// New +// TestOpaDecision_ValidRequest tests if the request is handled correctly +// Utility function to return a pointer to a string +func ptrString(s string) *string { + return &s +} + +// Utility function to return a pointer to a map +func ptrMap(m map[string]interface{}) *map[string]interface{} { + return &m +} + +// Utility function to return a pointer to a OPADecisionResponseDecision +func ptrOPADecisionResponseDecision(decision oapicodegen.OPADecisionResponseDecision) *oapicodegen.OPADecisionResponseDecision { + return &decision +} + +func TestWriteOpaJSONResponse(t *testing.T) { + rec := httptest.NewRecorder() + + // Use correct type for Decision, which is a pointer to OPADecisionResponseDecision + decision := oapicodegen.OPADecisionResponseDecision("PERMIT") + data := &oapicodegen.OPADecisionResponse{ + Decision: ptrOPADecisionResponseDecision(decision), // Correct use of pointer + PolicyName: ptrString("test-policy"), + Output: ptrMap(map[string]interface{}{"key": "value"}), + } + + writeOpaJSONResponse(rec, http.StatusOK, *data) + + assert.Equal(t, http.StatusOK, rec.Code) + assert.Contains(t, rec.Body.String(), `"decision":"PERMIT"`) + assert.Contains(t, rec.Body.String(), `"policyName":"test-policy"`) +} + +func TestWriteErrorJSONResponse(t *testing.T) { + rec := httptest.NewRecorder() + + // ErrorResponse struct uses pointers for string fields, so we use ptrString() + errorResponse := oapicodegen.ErrorResponse{ + ErrorMessage: ptrString("Bad Request"), + } + + writeErrorJSONResponse(rec, http.StatusBadRequest, "Bad Request", errorResponse) + + assert.Equal(t, http.StatusBadRequest, rec.Code) + assert.Contains(t, rec.Body.String(), `"errorMessage":"Bad Request"`) +} + +func TestCreateSuccessDecisionResponse(t *testing.T) { + // Input values for creating the response + statusMessage := "Success" + decision := oapicodegen.OPADecisionResponseDecision("PERMIT") + policyName := "policy-name" + output := map[string]interface{}{"key": "value"} + + // Call the createSuccessDecisionResponse function + response := createSuccessDecisionResponse(statusMessage, string(decision), policyName, output) + + // Assertions + + // Check the StatusMessage field + assert.Equal(t, *response.StatusMessage, statusMessage, "StatusMessage should match") + + // Check the Decision field (it should be a pointer to the string "PERMIT") + assert.Equal(t, *response.Decision, decision, "Decision should match") + + // Check the PolicyName field + assert.Equal(t, *response.PolicyName, policyName, "PolicyName should match") + + // Check the Output field + assert.Equal(t, *response.Output, output, "Output should match") +} + +func TestApplyPolicyFilter(t *testing.T) { + originalPolicy := map[string]interface{}{ + "policy1": map[string]interface{}{"key1": "value1"}, + "policy2": map[string]interface{}{"key2": "value2"}, + } + filter := []string{"policy1"} + result := applyPolicyFilter(originalPolicy, filter) + + assert.NotNil(t, result) + assert.Len(t, result, 1) + assert.Contains(t, result, "policy1") +} + +func TestWriteOpaJSONResponse_Error(t *testing.T) { + rec := httptest.NewRecorder() + + // Simulate an error response + statusMessage := "Error processing request" + decision := oapicodegen.OPADecisionResponseDecision("DENY") + policyName := "error-policy" + output := map[string]interface{}{"errorDetail": "Invalid input"} + + // Create a response object for error scenario + data := &oapicodegen.OPADecisionResponse{ + Decision: ptrOPADecisionResponseDecision(decision), // Use correct pointer + PolicyName: ptrString(policyName), + Output: ptrMap(output), + StatusMessage: ptrString(statusMessage), + } + + writeOpaJSONResponse(rec, http.StatusBadRequest, *data) + + // Assertions + assert.Equal(t, http.StatusBadRequest, rec.Code, "Expected HTTP 400 status code") + assert.Contains(t, rec.Body.String(), `"decision":"DENY"`, "Response should contain 'DENY' decision") + assert.Contains(t, rec.Body.String(), `"policyName":"error-policy"`, "Response should contain the policy name") + assert.Contains(t, rec.Body.String(), `"statusMessage":"Error processing request"`, "Response should contain the status message") + assert.Contains(t, rec.Body.String(), `"errorDetail":"Invalid input"`, "Response should contain the error detail") +} + +func TestWriteOpaJSONResponse_Success(t *testing.T) { + // Prepare test data + decisionRes := oapicodegen.OPADecisionResponse{ + StatusMessage: ptrString("Success"), + Decision: (*oapicodegen.OPADecisionResponseDecision)(ptrString("PERMIT")), + PolicyName: ptrString("TestPolicy"), + Output: &map[string]interface{}{"key": "value"}, + } + + // Create a mock HTTP response writer + res := httptest.NewRecorder() + + // Call the function + writeOpaJSONResponse(res, http.StatusOK, decisionRes) + + // Assert HTTP status + if res.Code != http.StatusOK { + t.Errorf("Expected status %d, got %d", http.StatusOK, res.Code) + } + + // Assert headers + if res.Header().Get("Content-Type") != "application/json" { + t.Errorf("Expected Content-Type 'application/json', got '%s'", res.Header().Get("Content-Type")) + } + + // Assert body + var result oapicodegen.OPADecisionResponse + if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + t.Fatalf("Failed to decode response body: %v", err) + } + if *result.StatusMessage != "Success" { + t.Errorf("Expected StatusMessage 'Success', got '%s'", *result.StatusMessage) + } +} + +func TestWriteOpaJSONResponse_EncodingError(t *testing.T) { + // Prepare invalid test data to trigger JSON encoding error + decisionRes := oapicodegen.OPADecisionResponse{ + // Introducing an invalid type to cause encoding failure + Output: &map[string]interface{}{"key": make(chan int)}, + } + + // Create a mock HTTP response writer + res := httptest.NewRecorder() + + // Call the function + writeOpaJSONResponse(res, http.StatusInternalServerError, decisionRes) + + // Assert HTTP status + if res.Code != http.StatusInternalServerError { + t.Errorf("Expected status %d, got %d", http.StatusInternalServerError, res.Code) + } + + // Assert error message in body + if !bytes.Contains(res.Body.Bytes(), []byte("json: unsupported type")) { + t.Errorf("Expected encoding error message, got '%s'", res.Body.String()) + } +} diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go index 4c8a13b..9a2a1a4 100644 --- a/pkg/healthcheck/healthcheck.go +++ b/pkg/healthcheck/healthcheck.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package healthcheck provides functionalities for handling health check requests. diff --git a/pkg/healthcheck/healthcheck_test.go b/pkg/healthcheck/healthcheck_test.go index 3e1876f..c8c4d15 100644 --- a/pkg/healthcheck/healthcheck_test.go +++ b/pkg/healthcheck/healthcheck_test.go @@ -1,3 +1,24 @@ +// - +// ========================LICENSE_START================================= +// Copyright (C) 2024: Deutsche Telekom +// +// 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=================================== + +// Package healthcheck provides functionalities for handling health check requests. +// This package includes a function to handle HTTP requests for health checks +// and respond with the health status of the service. package healthcheck import ( @@ -29,7 +50,7 @@ func TestHealthCheckHandler_Success(t *testing.T) { assert.Equal(t, pdpattributes.PdpName, *response.Name) assert.Equal(t, "self", *response.Url) assert.True(t, *response.Healthy) - assert.Equal(t,int32(200), *response.Code) + assert.Equal(t, int32(200), *response.Code) assert.Equal(t, "alive", *response.Message) } @@ -72,14 +93,94 @@ func TestHealthCheckHandler_Failure(t *testing.T) { } +func TestHealthCheckHandler_ValidUUID(t *testing.T) { + // Prepare a request with a valid UUID in the header + req := httptest.NewRequest(http.MethodGet, "/healthcheck", nil) + validUUID := "123e4567-e89b-12d3-a456-426614174000" + req.Header.Set("X-ONAP-RequestID", validUUID) + w := httptest.NewRecorder() + + // Call the HealthCheckHandler + HealthCheckHandler(w, req) + + // Check if the status code is OK (200) + assert.Equal(t, http.StatusOK, w.Code) + + // Check the response headers + assert.Equal(t, validUUID, w.Header().Get("X-ONAP-RequestID")) + + // Check the response body + var response oapicodegen.HealthCheckReport + err := json.NewDecoder(w.Body).Decode(&response) + assert.NoError(t, err) + assert.Equal(t, pdpattributes.PdpName, *response.Name) + assert.Equal(t, "self", *response.Url) + assert.True(t, *response.Healthy) + assert.Equal(t, int32(200), *response.Code) + assert.Equal(t, "alive", *response.Message) +} + +func TestHealthCheckHandler_InvalidUUID(t *testing.T) { + // Prepare a request with an invalid UUID in the header + req := httptest.NewRequest(http.MethodGet, "/healthcheck", nil) + req.Header.Set("X-ONAP-RequestID", "invalid-uuid") + w := httptest.NewRecorder() + + // Call the HealthCheckHandler + HealthCheckHandler(w, req) + + // Check if the status code is OK (200) + assert.Equal(t, http.StatusOK, w.Code) + + // Check the fallback request ID + assert.Equal(t, "000000000000", w.Header().Get("X-ONAP-RequestID")) +} + +func TestHealthCheckHandler_MissingUUID(t *testing.T) { + // Prepare a request with no UUID header + req := httptest.NewRequest(http.MethodGet, "/healthcheck", nil) + w := httptest.NewRecorder() + + // Call the HealthCheckHandler + HealthCheckHandler(w, req) + + // Check if the status code is OK (200) + assert.Equal(t, http.StatusOK, w.Code) + + // Check the fallback request ID + assert.Equal(t, "000000000000", w.Header().Get("X-ONAP-RequestID")) +} + +func TestHealthCheckHandler_EmptyResponseBody(t *testing.T) { + // Simulate a case where the handler fails to set the response body + EmptyResponseHandler := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + } + + // Prepare a request to the health check endpoint + req := httptest.NewRequest(http.MethodGet, "/healthcheck", nil) + w := httptest.NewRecorder() + + // Call the modified handler + EmptyResponseHandler(w, req) + + // Check if the status code is OK (200) + assert.Equal(t, http.StatusOK, w.Code) + + // Try decoding the empty body + var response oapicodegen.HealthCheckReport + err := json.NewDecoder(w.Body).Decode(&response) + assert.Error(t, err) +} + func strPtr(s string) *string { - return &s + return &s } func boolPtr(b bool) *bool { - return &b + return &b } func int32Ptr(i int32) *int32 { - return &i + return &i } diff --git a/pkg/kafkacomm/handler/pdp_message_handler.go b/pkg/kafkacomm/handler/pdp_message_handler.go index 8d7da92..8d1b9b4 100644 --- a/pkg/kafkacomm/handler/pdp_message_handler.go +++ b/pkg/kafkacomm/handler/pdp_message_handler.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // The handler package is responsible for processing messages from Kafka, specifically targeting the OPA @@ -22,14 +23,35 @@ package handler import ( + "context" "encoding/json" "policy-opa-pdp/consts" "policy-opa-pdp/pkg/kafkacomm" "policy-opa-pdp/pkg/kafkacomm/publisher" "policy-opa-pdp/pkg/log" "policy-opa-pdp/pkg/pdpattributes" + "sync" ) +var ( + shutdownFlag bool + mu sync.Mutex +) + +// SetShutdownFlag sets the shutdown flag +func SetShutdownFlag() { + mu.Lock() + shutdownFlag = true + mu.Unlock() +} + +// IsShutdown checks if the consumer has already been shut down +func IsShutdown() bool { + mu.Lock() + defer mu.Unlock() + return shutdownFlag +} + type OpaPdpMessage struct { Name string `json:"name"` // Name of the PDP (optional for broadcast messages). MessageType string `json:"MessageName"` // Type of the message (e.g., PDP_UPDATE, PDP_STATE_CHANGE, etc.) @@ -74,58 +96,65 @@ func checkIfMessageIsForOpaPdp(message OpaPdpMessage) bool { // Handles incoming Kafka messages, validates their relevance to the current PDP, // and dispatches them for further processing based on their type. -func PdpMessageHandler(kc *kafkacomm.KafkaConsumer, topic string, p publisher.PdpStatusSender) error { +func PdpMessageHandler(ctx context.Context, kc *kafkacomm.KafkaConsumer, topic string, p publisher.PdpStatusSender) error { log.Debug("Starting PDP Message Listener.....") var stopConsuming bool for !stopConsuming { - message, err := kafkacomm.ReadKafkaMessages(kc) - if err != nil { - log.Warnf("Failed to Read Kafka Messages: %v\n", err) - continue - } - log.Debugf("[IN|KAFKA|%s]\n%s", topic, string(message)) - - if message != nil { - - var opaPdpMessage OpaPdpMessage - - err = json.Unmarshal(message, &opaPdpMessage) + select { + case <-ctx.Done(): + log.Debug("Stopping PDP Listener.....") + return nil + stopConsuming = true ///Loop Exits + default: + message, err := kafkacomm.ReadKafkaMessages(kc) if err != nil { - log.Warnf("Failed to UnMarshal Messages: %v\n", err) continue } + log.Debugf("[IN|KAFKA|%s]\n%s", topic, string(message)) - if !checkIfMessageIsForOpaPdp(opaPdpMessage) { - - log.Warnf("Not a valid Opa Pdp Message") - continue - } + if message != nil { - switch opaPdpMessage.MessageType { + var opaPdpMessage OpaPdpMessage - case "PDP_UPDATE": - err = PdpUpdateMessageHandler(message, p) + err = json.Unmarshal(message, &opaPdpMessage) if err != nil { - log.Warnf("Error processing Update Message: %v", err) + log.Warnf("Failed to UnMarshal Messages: %v\n", err) + continue } - case "PDP_STATE_CHANGE": - err = PdpStateChangeMessageHandler(message, p) - if err != nil { - log.Warnf("Error processing Update Message: %v", err) + if !checkIfMessageIsForOpaPdp(opaPdpMessage) { + + log.Warnf("Not a valid Opa Pdp Message") + continue } - case "PDP_STATUS": - log.Debugf("discarding event of type PDP_STATUS") - continue - default: - log.Errorf("This is not a valid Message Type: %s", opaPdpMessage.MessageType) - continue + switch opaPdpMessage.MessageType { - } + case "PDP_UPDATE": + err = PdpUpdateMessageHandler(message, p) + if err != nil { + log.Warnf("Error processing Update Message: %v", err) + } + case "PDP_STATE_CHANGE": + err = PdpStateChangeMessageHandler(message, p) + if err != nil { + log.Warnf("Error processing Update Message: %v", err) + } + + case "PDP_STATUS": + log.Debugf("discarding event of type PDP_STATUS") + continue + default: + log.Errorf("This is not a valid Message Type: %s", opaPdpMessage.MessageType) + continue + + } + + } } + } return nil diff --git a/pkg/kafkacomm/handler/pdp_message_handler_test.go b/pkg/kafkacomm/handler/pdp_message_handler_test.go index 3764c9e..8ba1e0e 100644 --- a/pkg/kafkacomm/handler/pdp_message_handler_test.go +++ b/pkg/kafkacomm/handler/pdp_message_handler_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // @@ -20,8 +21,13 @@ package handler import ( "github.com/stretchr/testify/assert" + "policy-opa-pdp/consts" "policy-opa-pdp/pkg/pdpattributes" "testing" + // "context" + // "encoding/json" + // "errors" + // "policy-opa-pdp/pkg/kafkacomm/mocks" ) /* @@ -36,7 +42,7 @@ func TestCheckIfMessageIsForOpaPdp_Check(t *testing.T) { opapdpMessage.Name = "opa-3a318049-813f-4172-b4d3-7d4f466e5b80" opapdpMessage.MessageType = "PDP_STATUS" - opapdpMessage.PdpGroup = "defaultGroup" + opapdpMessage.PdpGroup = "opaGroup" opapdpMessage.PdpSubgroup = "opa" assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Its a valid Opa Pdp Message") @@ -55,7 +61,7 @@ func TestCheckIfMessageIsForOpaPdp_Check_Message_Name(t *testing.T) { opapdpMessage.Name = "" opapdpMessage.MessageType = "PDP_STATUS" - opapdpMessage.PdpGroup = "defaultGroup" + opapdpMessage.PdpGroup = "opaGroup" opapdpMessage.PdpSubgroup = "opa" assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Not a valid Opa Pdp Message") @@ -74,7 +80,7 @@ func TestCheckIfMessageIsForOpaPdp_Check_PdpGroup(t *testing.T) { opapdpMessage.Name = "" opapdpMessage.MessageType = "PDP_STATUS" - opapdpMessage.PdpGroup = "defaultGroup" + opapdpMessage.PdpGroup = "opaGroup" opapdpMessage.PdpSubgroup = "opa" pdpattributes.PdpSubgroup = "opa" @@ -113,7 +119,7 @@ func TestCheckIfMessageIsForOpaPdp_Check_PdpSubgroup(t *testing.T) { opapdpMessage.Name = "" opapdpMessage.MessageType = "PDP_STATUS" - opapdpMessage.PdpGroup = "defaultGroup" + opapdpMessage.PdpGroup = "opaGroup" opapdpMessage.PdpSubgroup = "opa" pdpattributes.PdpSubgroup = "opa" @@ -133,10 +139,53 @@ func TestCheckIfMessageIsForOpaPdp_Check_IncorrectPdpSubgroup(t *testing.T) { opapdpMessage.Name = "" opapdpMessage.MessageType = "PDP_STATUS" - opapdpMessage.PdpGroup = "defaultGroup" + opapdpMessage.PdpGroup = "opaGroup" opapdpMessage.PdpSubgroup = "o" pdpattributes.PdpSubgroup = "opa" assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Not a valid Opa Pdp Message") } + +func TestCheckIfMessageIsForOpaPdp_EmptyPdpSubgroupAndGroup(t *testing.T) { + var opapdpMessage OpaPdpMessage + opapdpMessage.Name = "" + opapdpMessage.MessageType = "PDP_STATUS" + opapdpMessage.PdpGroup = "" + opapdpMessage.PdpSubgroup = "" + + assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Message should be invalid when PdpGroup and PdpSubgroup are empty") +} + +func TestCheckIfMessageIsForOpaPdp_ValidBroadcastMessage(t *testing.T) { + var opapdpMessage OpaPdpMessage + opapdpMessage.Name = "" + opapdpMessage.MessageType = "PDP_UPDATE" + opapdpMessage.PdpGroup = "opaGroup" + opapdpMessage.PdpSubgroup = "" + + pdpattributes.PdpSubgroup = "opa" + consts.PdpGroup = "opaGroup" + + assert.True(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Valid broadcast message should pass the check") +} + +func TestCheckIfMessageIsForOpaPdp_InvalidGroupMismatch(t *testing.T) { + var opapdpMessage OpaPdpMessage + opapdpMessage.Name = "" + opapdpMessage.MessageType = "PDP_STATUS" + opapdpMessage.PdpGroup = "wrongGroup" + opapdpMessage.PdpSubgroup = "" + + consts.PdpGroup = "opaGroup" + + assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Message with mismatched PdpGroup should fail") +} + +// Test SetShutdownFlag and IsShutdown +func TestSetAndCheckShutdownFlag(t *testing.T) { + assert.False(t, IsShutdown(), "Shutdown flag should be false initially") + + SetShutdownFlag() + assert.True(t, IsShutdown(), "Shutdown flag should be true after calling SetShutdownFlag") +} diff --git a/pkg/kafkacomm/handler/pdp_state_change_handler.go b/pkg/kafkacomm/handler/pdp_state_change_handler.go index 32d998f..2de89ff 100644 --- a/pkg/kafkacomm/handler/pdp_state_change_handler.go +++ b/pkg/kafkacomm/handler/pdp_state_change_handler.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // will process the state change message from pap and send the pdp status response. diff --git a/pkg/kafkacomm/handler/pdp_state_change_handler_test.go b/pkg/kafkacomm/handler/pdp_state_change_handler_test.go index f7e8f84..67edd6f 100644 --- a/pkg/kafkacomm/handler/pdp_state_change_handler_test.go +++ b/pkg/kafkacomm/handler/pdp_state_change_handler_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/kafkacomm/handler/pdp_update_message_handler.go b/pkg/kafkacomm/handler/pdp_update_message_handler.go index 632bcc8..efe115c 100644 --- a/pkg/kafkacomm/handler/pdp_update_message_handler.go +++ b/pkg/kafkacomm/handler/pdp_update_message_handler.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // will process the update message from pap and send the pdp status response. diff --git a/pkg/kafkacomm/handler/pdp_update_message_handler_test.go b/pkg/kafkacomm/handler/pdp_update_message_handler_test.go index 061f1ce..4d5d7dc 100644 --- a/pkg/kafkacomm/handler/pdp_update_message_handler_test.go +++ b/pkg/kafkacomm/handler/pdp_update_message_handler_test.go @@ -1,6 +1,5 @@ -// - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +12,7 @@ // 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=================================== // @@ -43,7 +43,7 @@ func TestPdpUpdateMessageHandler_Success(t *testing.T) { "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1", "timestampMs":1730722305297, "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059", - "pdpGroup":"defaultGroup", + "pdpGroup":"opaGroup", "pdpSubgroup":"opa" }` @@ -154,7 +154,7 @@ func TestPdpUpdateMessageHandler_Fails_Sending_UpdateResponse(t *testing.T) { "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1", "timestampMs":1730722305297, "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059", - "pdpGroup":"defaultGroup" + "pdpGroup":"opaGroup" }` mockSender := new(mocks.PdpStatusSender) @@ -183,7 +183,7 @@ func TestPdpUpdateMessageHandler_Invalid_Starttimeinterval(t *testing.T) { "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1", "timestampMs":1730722305297, "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059", - "pdpGroup":"defaultGroup", + "pdpGroup":"opaGroup", "pdpSubgroup":"opa" }` diff --git a/pkg/kafkacomm/pdp_topic_consumer.go b/pkg/kafkacomm/pdp_topic_consumer.go index 4858bdf..3d19e6c 100644 --- a/pkg/kafkacomm/pdp_topic_consumer.go +++ b/pkg/kafkacomm/pdp_topic_consumer.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // kafkacomm package provides a structured way to create and manage Kafka consumers, @@ -20,12 +21,20 @@ package kafkacomm import ( + "fmt" "github.com/confluentinc/confluent-kafka-go/kafka" "policy-opa-pdp/cfg" "policy-opa-pdp/pkg/log" + "sync" "time" ) +var ( + // Declare a global variable to hold the singleton KafkaConsumer + consumerInstance *KafkaConsumer + consumerOnce sync.Once // sync.Once ensures that the consumer is created only once +) + // KafkaConsumerInterface defines the interface for a Kafka consumer. type KafkaConsumerInterface interface { Close() error @@ -40,63 +49,92 @@ type KafkaConsumer struct { // Close closes the KafkaConsumer func (kc *KafkaConsumer) Close() { - kc.Consumer.Close() + if kc.Consumer != nil { + kc.Consumer.Close() + } } // Unsubscribe unsubscribes the KafkaConsumer func (kc *KafkaConsumer) Unsubscribe() error { - if err := kc.Consumer.Unsubscribe(); err != nil { - log.Warnf("Error Unsubscribing :%v", err) + if kc.Consumer == nil { + return fmt.Errorf("Kafka Consumer is nil so cannot Unsubscribe") + } + err := kc.Consumer.Unsubscribe() + if err != nil { + log.Warnf("Error Unsubscribing: %v", err) return err } - log.Debug("Unsubscribe From Topic") + log.Debug("Unsubscribed From Topic") return nil } -// creates a new Kafka consumer and returns it +// NewKafkaConsumer creates a new Kafka consumer and returns it func NewKafkaConsumer() (*KafkaConsumer, error) { - brokers := cfg.BootstrapServer - groupid := cfg.GroupId - topic := cfg.Topic - useSASL := cfg.UseSASLForKAFKA - username := cfg.KAFKA_USERNAME - password := cfg.KAFKA_PASSWORD + // Initialize the consumer instance only once + consumerOnce.Do(func() { + log.Debugf("Creating Kafka Consumer singleton instance") + brokers := cfg.BootstrapServer + groupid := cfg.GroupId + topic := cfg.Topic + useSASL := cfg.UseSASLForKAFKA + username := cfg.KAFKA_USERNAME + password := cfg.KAFKA_PASSWORD - // Add Kafka Connection Properties .... - configMap := &kafka.ConfigMap{ - "bootstrap.servers": brokers, - "group.id": groupid, - "auto.offset.reset": "earliest", - } - //for STRIMZI-KAFKA in case sasl is enabled - if useSASL == "true" { - configMap.SetKey("sasl.mechanism", "SCRAM-SHA-512") - configMap.SetKey("sasl.username", username) - configMap.SetKey("sasl.password", password) - configMap.SetKey("security.protocol", "SASL_PLAINTEXT") - } + // Add Kafka connection properties + configMap := &kafka.ConfigMap{ + "bootstrap.servers": brokers, + "group.id": groupid, + "auto.offset.reset": "latest", + } - // create new Kafka Consumer - consumer, err := kafka.NewConsumer(configMap) - if err != nil { - log.Warnf("Error creating consumer: %v\n", err) - return nil, err - } - //subscribe to topic - err = consumer.SubscribeTopics([]string{topic}, nil) - if err != nil { - log.Warnf("Error subcribing to topic: %v\n", err) - return nil, err + // If SASL is enabled, add SASL properties + if useSASL == "true" { + configMap.SetKey("sasl.mechanism", "SCRAM-SHA-512") + configMap.SetKey("sasl.username", username) + configMap.SetKey("sasl.password", password) + configMap.SetKey("security.protocol", "SASL_PLAINTEXT") + configMap.SetKey("session.timeout.ms", "30000") + configMap.SetKey("max.poll.interval.ms", "300000") + configMap.SetKey("enable.partition.eof", true) + configMap.SetKey("enable.auto.commit", true) + // configMap.SetKey("debug", "all") // Uncomment for debug + } + + // Create a new Kafka consumer + consumer, err := kafka.NewConsumer(configMap) + if err != nil { + log.Warnf("Error creating consumer: %v", err) + return + } + if consumer == nil { + log.Warnf("Kafka Consumer is nil after creation") + return + } + + // Subscribe to the topic + err = consumer.SubscribeTopics([]string{topic}, nil) + if err != nil { + log.Warnf("Error subscribing to topic: %v", err) + return + } + log.Debugf("Topic Subscribed: %v", topic) + + // Assign the consumer instance + consumerInstance = &KafkaConsumer{Consumer: consumer} + log.Debugf("Created SIngleton consumer instance") + }) + + // Return the singleton consumer instance + if consumerInstance == nil { + return nil, fmt.Errorf("Kafka Consumer instance not created") } - log.Debugf("Topic Subscribed... : %v", topic) - return &KafkaConsumer{Consumer: consumer}, nil + return consumerInstance, nil } -// gets the Kafka messages on the subscribed topic +// ReadKafkaMessages gets the Kafka messages on the subscribed topic func ReadKafkaMessages(kc *KafkaConsumer) ([]byte, error) { - msg, err := kc.Consumer.ReadMessage(-1) + msg, err := kc.Consumer.ReadMessage(100 * time.Millisecond) if err != nil { - log.Warnf("Error reading Kafka message: %v", err) return nil, err } return msg.Value, nil diff --git a/pkg/kafkacomm/pdp_topic_consumer_test.go b/pkg/kafkacomm/pdp_topic_consumer_test.go index 2fdfa90..9feeeaa 100644 --- a/pkg/kafkacomm/pdp_topic_consumer_test.go +++ b/pkg/kafkacomm/pdp_topic_consumer_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/kafkacomm/pdp_topic_producer.go b/pkg/kafkacomm/pdp_topic_producer.go index 1b11b35..d8edb0b 100644 --- a/pkg/kafkacomm/pdp_topic_producer.go +++ b/pkg/kafkacomm/pdp_topic_producer.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package kafkacomm provides utilities for producing messages to a Kafka topic @@ -22,9 +23,9 @@ package kafkacomm import ( "github.com/confluentinc/confluent-kafka-go/kafka" + "log" "policy-opa-pdp/cfg" "sync" - "log" ) type KafkaProducerInterface interface { diff --git a/pkg/kafkacomm/pdp_topic_producer_test.go b/pkg/kafkacomm/pdp_topic_producer_test.go index 55f3bc8..3379845 100644 --- a/pkg/kafkacomm/pdp_topic_producer_test.go +++ b/pkg/kafkacomm/pdp_topic_producer_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/kafkacomm/publisher/pdp-heartbeat.go b/pkg/kafkacomm/publisher/pdp-heartbeat.go index f814992..fbd07d6 100644 --- a/pkg/kafkacomm/publisher/pdp-heartbeat.go +++ b/pkg/kafkacomm/publisher/pdp-heartbeat.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // The publisher package is responsible for managing periodic heartbeat messages for the @@ -55,7 +56,7 @@ func StartHeartbeatIntervalTimer(intervalMs int64, s PdpStatusSender) { if ticker != nil { ticker.Stop() } - // StopTicker() + // StopTicker() currentInterval = intervalMs ticker = time.NewTicker(time.Duration(intervalMs) * time.Millisecond) diff --git a/pkg/kafkacomm/publisher/pdp-heartbeat_test.go b/pkg/kafkacomm/publisher/pdp-heartbeat_test.go index f03b0eb..e95866e 100644 --- a/pkg/kafkacomm/publisher/pdp-heartbeat_test.go +++ b/pkg/kafkacomm/publisher/pdp-heartbeat_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/kafkacomm/publisher/pdp-pap-registration.go b/pkg/kafkacomm/publisher/pdp-pap-registration.go index 75f22d6..54b12ea 100644 --- a/pkg/kafkacomm/publisher/pdp-pap-registration.go +++ b/pkg/kafkacomm/publisher/pdp-pap-registration.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // allows to send the pdp registartion message with unique transaction id and timestamp to topic diff --git a/pkg/kafkacomm/publisher/pdp-pap-registration_test.go b/pkg/kafkacomm/publisher/pdp-pap-registration_test.go index 03749de..725b4b9 100644 --- a/pkg/kafkacomm/publisher/pdp-pap-registration_test.go +++ b/pkg/kafkacomm/publisher/pdp-pap-registration_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/kafkacomm/publisher/pdp-status-publisher.go b/pkg/kafkacomm/publisher/pdp-status-publisher.go index 756d0f2..4a13b1c 100644 --- a/pkg/kafkacomm/publisher/pdp-status-publisher.go +++ b/pkg/kafkacomm/publisher/pdp-status-publisher.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/kafkacomm/publisher/pdp-status-publisher_test.go b/pkg/kafkacomm/publisher/pdp-status-publisher_test.go index 5e02704..83154ca 100644 --- a/pkg/kafkacomm/publisher/pdp-status-publisher_test.go +++ b/pkg/kafkacomm/publisher/pdp-status-publisher_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/log/log.go b/pkg/log/log.go index 2a8b997..73f2d38 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index d24274c..6e7e41a 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/metrics/counters.go b/pkg/metrics/counters.go index 2fc9539..bbf148b 100644 --- a/pkg/metrics/counters.go +++ b/pkg/metrics/counters.go @@ -1,12 +1,33 @@ +// - +// ========================LICENSE_START================================= +// Copyright (C) 2024: Deutsche Telekom +// +// 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=================================== +// + package metrics import "sync" -//global counter variables +// global counter variables var IndeterminantDecisionsCount int64 var PermitDecisionsCount int64 var DenyDecisionsCount int64 var TotalErrorCount int64 +var QuerySuccessCount int64 +var QueryFailureCount int64 var mu sync.Mutex // Increment counter @@ -64,3 +85,33 @@ func TotalErrorCountRef() *int64 { defer mu.Unlock() return &TotalErrorCount } + +// Increment counter +func IncrementQuerySuccessCount() { + mu.Lock() + QuerySuccessCount++ + mu.Unlock() +} + +// returns pointer to the counter +func TotalQuerySuccessCountRef() *int64 { + mu.Lock() + defer mu.Unlock() + return &QuerySuccessCount + +} + +// Increment counter +func IncrementQueryFailureCount() { + mu.Lock() + QueryFailureCount++ + mu.Unlock() +} + +// returns pointer to the counter +func TotalQueryFailureCountRef() *int64 { + mu.Lock() + defer mu.Unlock() + return &QueryFailureCount + +} diff --git a/pkg/metrics/counters_test.go b/pkg/metrics/counters_test.go index ef4c2b0..41a30e1 100644 --- a/pkg/metrics/counters_test.go +++ b/pkg/metrics/counters_test.go @@ -1,3 +1,22 @@ +// - +// ========================LICENSE_START================================= +// Copyright (C) 2024: Deutsche Telekom +// +// 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=================================== +// + package metrics import ( diff --git a/pkg/metrics/statistics-provider.go b/pkg/metrics/statistics-provider.go index 67cee79..ba55b27 100644 --- a/pkg/metrics/statistics-provider.go +++ b/pkg/metrics/statistics-provider.go @@ -1,3 +1,22 @@ +// - +// ========================LICENSE_START================================= +// Copyright (C) 2024: Deutsche Telekom +// +// 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=================================== +// + // Handles an HTTP request to fetch the current system statistics. // It aggregates various decision counts (e.g., indeterminate, permit, deny) // and error counts into a structured response and sends it back to the client in JSON format. @@ -43,6 +62,8 @@ func FetchCurrentStatistics(res http.ResponseWriter, req *http.Request) { statReport.PermitDecisionsCount = PermitDecisionsCountRef() statReport.DenyDecisionsCount = DenyDecisionsCountRef() statReport.TotalErrorCount = TotalErrorCountRef() + statReport.QuerySuccessCount = TotalQuerySuccessCountRef() + statReport.QueryFailureCount = TotalQueryFailureCountRef() // not implemented hardcoding the values to zero // will be implemeneted in phase-2 diff --git a/pkg/metrics/statistics-provider_test.go b/pkg/metrics/statistics-provider_test.go index a5e57b6..4e2cff4 100644 --- a/pkg/metrics/statistics-provider_test.go +++ b/pkg/metrics/statistics-provider_test.go @@ -1,3 +1,22 @@ +// - +// ========================LICENSE_START================================= +// Copyright (C) 2024: Deutsche Telekom +// +// 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=================================== +// + package metrics import ( diff --git a/pkg/model/healthcheckmessage.go b/pkg/model/healthcheckmessage.go index 8b0d9db..df22a65 100644 --- a/pkg/model/healthcheckmessage.go +++ b/pkg/model/healthcheckmessage.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,15 +13,16 @@ // 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=================================== // - + package model - + type HealthCheckResponse struct { - Name string `json:"name"` - Url string `json:"url"` - Healthy bool `json:"healthy"` - Code int `json:"code"` - Message string `json:"message"` + Name string `json:"name"` + Url string `json:"url"` + Healthy bool `json:"healthy"` + Code int `json:"code"` + Message string `json:"message"` } diff --git a/pkg/model/mesages.go b/pkg/model/mesages.go index a4451d7..269f45f 100644 --- a/pkg/model/mesages.go +++ b/pkg/model/mesages.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Defines structure for messages exchanged between PDP and PAP @@ -65,35 +66,35 @@ func (p PdpMessageType) MarshalJSON() ([]byte, error) { // https://github.com/onap/policy-models // models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpStatus.java type PdpStatus struct { - MessageType PdpMessageType `json:"messageName"` - PdpType string `json:"pdpType"` - State PdpState `json:"state"` - Healthy PdpHealthStatus `json:"healthy"` - Description string `json:"description"` - PdpResponse *PdpResponseDetails `json:"response"` - Policies []ToscaConceptIdentifier `json:"policies"` - Name string `json:"name"` - RequestID string `json:"requestId"` - PdpGroup string `json:"pdpGroup"` - PdpSubgroup *string `json:"pdpSubgroup"` - TimestampMs string `json:"timestampMs"` - DeploymentInstanceInfo string `json:"deploymentInstanceInfo"` + MessageType PdpMessageType `json:"messageName"` + PdpType string `json:"pdpType"` + State PdpState `json:"state"` + Healthy PdpHealthStatus `json:"healthy"` + Description string `json:"description"` + PdpResponse *PdpResponseDetails `json:"response"` + Policies []ToscaConceptIdentifier `json:"policies"` + Name string `json:"name"` + RequestID string `json:"requestId"` + PdpGroup string `json:"pdpGroup"` + PdpSubgroup *string `json:"pdpSubgroup"` + TimestampMs string `json:"timestampMs"` + DeploymentInstanceInfo string `json:"deploymentInstanceInfo"` } // PDP_UPDATE sent by PAP to PDP. // https://github.com/onap/policy-models // models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpUpdate.java type PdpUpdate struct { - Source string `json:"source" validate:"required"` - PdpHeartbeatIntervalMs int64 `json:"pdpHeartbeatIntervalMs" validate:"required"` - MessageType string `json:"messageName" validate:"required"` - PoliciesToBeDeloyed []string `json:"policiesToBeDeployed" validate:"required"` - policiesToBeUndeployed []ToscaConceptIdentifier `json:"policiesToBeUndeployed"` - Name string `json:"name" validate:"required"` - TimestampMs int64 `json:"timestampMs" validate:"required"` - PdpGroup string `json:"pdpGroup" validate:"required"` - PdpSubgroup string `json:"pdpSubgroup" validate:"required"` - RequestId string `json:"requestId" validate:"required"` + Source string `json:"source" validate:"required"` + PdpHeartbeatIntervalMs int64 `json:"pdpHeartbeatIntervalMs" validate:"required"` + MessageType string `json:"messageName" validate:"required"` + PoliciesToBeDeloyed []string `json:"policiesToBeDeployed" validate:"required"` + policiesToBeUndeployed []ToscaConceptIdentifier `json:"policiesToBeUndeployed"` + Name string `json:"name" validate:"required"` + TimestampMs int64 `json:"timestampMs" validate:"required"` + PdpGroup string `json:"pdpGroup" validate:"required"` + PdpSubgroup string `json:"pdpSubgroup" validate:"required"` + RequestId string `json:"requestId" validate:"required"` } // PDP_STATE_CHANGE sent by PAP to PDP. diff --git a/pkg/model/messages_test.go b/pkg/model/messages_test.go index f6bb5ca..4853901 100644 --- a/pkg/model/messages_test.go +++ b/pkg/model/messages_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/model/oapicodegen/models.go b/pkg/model/oapicodegen/models.go index 4f1b770..b6dc75e 100644 --- a/pkg/model/oapicodegen/models.go +++ b/pkg/model/oapicodegen/models.go @@ -1,4 +1,4 @@ -// Package api provides primitives to interact with the openapi HTTP API. +// Package oapicodegen provides primitives to interact with the openapi HTTP API. // // Code generated by github.com/deepmap/oapi-codegen version v1.16.3 DO NOT EDIT. package oapicodegen @@ -45,6 +45,7 @@ const ( const ( DENY OPADecisionResponseDecision = "DENY" INDETERMINATE OPADecisionResponseDecision = "INDETERMINATE" + NOTAPPLICABLE OPADecisionResponseDecision = "NOTAPPLICABLE" PERMIT OPADecisionResponseDecision = "PERMIT" ) @@ -77,6 +78,7 @@ type OPADecisionRequest struct { OnapComponent *string `json:"onapComponent,omitempty"` OnapInstance *string `json:"onapInstance,omitempty"` OnapName *string `json:"onapName,omitempty"` + PolicyFilter *[]string `json:"policyFilter,omitempty"` PolicyName *string `json:"policyName,omitempty"` // TimeOffset Time offset in hours and minutes, e.g., '+02:00' or '-05:00' @@ -89,6 +91,7 @@ type OPADecisionRequest struct { // OPADecisionResponse defines model for OPADecisionResponse. type OPADecisionResponse struct { Decision *OPADecisionResponseDecision `json:"decision,omitempty"` + Output *map[string]interface{} `json:"output,omitempty"` PolicyName *string `json:"policyName,omitempty"` StatusMessage *string `json:"statusMessage,omitempty"` } @@ -104,6 +107,8 @@ type StatisticsReport struct { DeploySuccessCount *int64 `json:"deploySuccessCount,omitempty"` IndeterminantDecisionsCount *int64 `json:"indeterminantDecisionsCount,omitempty"` PermitDecisionsCount *int64 `json:"permitDecisionsCount,omitempty"` + QueryFailureCount *int64 `json:"queryFailureCount,omitempty"` + QuerySuccessCount *int64 `json:"querySuccessCount,omitempty"` TotalErrorCount *int64 `json:"totalErrorCount,omitempty"` TotalPoliciesCount *int64 `json:"totalPoliciesCount,omitempty"` TotalPolicyTypesCount *int64 `json:"totalPolicyTypesCount,omitempty"` diff --git a/pkg/model/pdphealthstatus.go b/pkg/model/pdphealthstatus.go index 387a1e8..6560f49 100644 --- a/pkg/model/pdphealthstatus.go +++ b/pkg/model/pdphealthstatus.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // the possible values for health status of PDP. diff --git a/pkg/model/pdphealthstatus_test.go b/pkg/model/pdphealthstatus_test.go index 0cb89cf..007939f 100644 --- a/pkg/model/pdphealthstatus_test.go +++ b/pkg/model/pdphealthstatus_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/model/pdpresponsedetails.go b/pkg/model/pdpresponsedetails.go index 8febae5..b9557f5 100644 --- a/pkg/model/pdpresponsedetails.go +++ b/pkg/model/pdpresponsedetails.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // represent PDP response details. diff --git a/pkg/model/pdpresponsedetails_test.go b/pkg/model/pdpresponsedetails_test.go index 14b9cd8..5402fef 100644 --- a/pkg/model/pdpresponsedetails_test.go +++ b/pkg/model/pdpresponsedetails_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/model/pdpstate.go b/pkg/model/pdpstate.go index 2b54d16..040498b 100644 --- a/pkg/model/pdpstate.go +++ b/pkg/model/pdpstate.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // hold the possible values for state of PDP. diff --git a/pkg/model/pdpstate_test.go b/pkg/model/pdpstate_test.go index 35ff6af..5881743 100644 --- a/pkg/model/pdpstate_test.go +++ b/pkg/model/pdpstate_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/model/toscaconceptidentifier.go b/pkg/model/toscaconceptidentifier.go index 7afc7b1..c9d7788 100644 --- a/pkg/model/toscaconceptidentifier.go +++ b/pkg/model/toscaconceptidentifier.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Identifies a concept. Both the name and version must be non-null. diff --git a/pkg/model/toscaconceptidentifier_test.go b/pkg/model/toscaconceptidentifier_test.go index a131483..f05b315 100644 --- a/pkg/model/toscaconceptidentifier_test.go +++ b/pkg/model/toscaconceptidentifier_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/opasdk/opasdk.go b/pkg/opasdk/opasdk.go index da6c7cc..51a34e7 100644 --- a/pkg/opasdk/opasdk.go +++ b/pkg/opasdk/opasdk.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // The opasdk package provides functionalities for integrating with the Open Policy Agent diff --git a/pkg/opasdk/opasdk_test.go b/pkg/opasdk/opasdk_test.go index b6c205b..0507b07 100644 --- a/pkg/opasdk/opasdk_test.go +++ b/pkg/opasdk/opasdk_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/pdpattributes/pdpattributes.go b/pkg/pdpattributes/pdpattributes.go index 70744fd..8ce738b 100644 --- a/pkg/pdpattributes/pdpattributes.go +++ b/pkg/pdpattributes/pdpattributes.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // The pdpattributes package provides utilities for managing and configuring attributes related to the diff --git a/pkg/pdpattributes/pdpattributes_test.go b/pkg/pdpattributes/pdpattributes_test.go index 0870ed6..909b4ee 100644 --- a/pkg/pdpattributes/pdpattributes_test.go +++ b/pkg/pdpattributes/pdpattributes_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/pdpstate/pdpstate.go b/pkg/pdpstate/pdpstate.go index 0adaa2e..c7aaccb 100644 --- a/pkg/pdpstate/pdpstate.go +++ b/pkg/pdpstate/pdpstate.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // The pdpstate package manages the state of the Policy Decision Point (PDP), allowing for dynamic updates diff --git a/pkg/pdpstate/pdpstate_test.go b/pkg/pdpstate/pdpstate_test.go index 6b7078c..11277dd 100644 --- a/pkg/pdpstate/pdpstate_test.go +++ b/pkg/pdpstate/pdpstate_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index c2cb591..9b405d5 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== // Package utils provides common functionalities diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index b70fa2b..d8d630b 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -1,6 +1,6 @@ // - // ========================LICENSE_START================================= -// Copyright (C) 2024: Deutsche Telecom +// Copyright (C) 2024: Deutsche Telekom // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ // 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=================================== package utils diff --git a/test/README.md b/test/README.md index 7940342..1052749 100644 --- a/test/README.md +++ b/test/README.md @@ -41,6 +41,44 @@ curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: {"decision":"DENY","policyName":"organization/allow","statusMessage":"OPA Denied"} +## DENY for policy:abac(output) + +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"abac", "policyFilter": ["action_is_read"], "input":{"actions": ["write"],"datatypes": ["location","temperature","precipitation","windspeed"],"time_period": {"from": "2024-03-27","to": "2024-03-31"}}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision +{"decision":"DENY","output":{},"policyName":"abac","statusMessage":"OPA Denied"} + +## PERMIT for policy:abac + +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"abac", "policyFilter": ["viewable_sensor_data"], "input":{"actions": ["read"],"datatypes": ["location","temperature","precipitation","windspeed"],"time_period": {"from": "2024-02-27","to": "2024-02-29"}}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision +{"decision":"PERMIT","output":{"viewable_sensor_data":[{"location":"Galle","precipitation":"500 mm","temperature":"35 C","windspeed":"7.2 m/s"},{"location":"Jaffna","precipitation":"300 mm","temperature":"-5 C","windspeed":"3.8 m/s"},{"location":"Nuwara Eliya","precipitation":"600 mm","temperature":"25 C","windspeed":"4.0 m/s"},{"location":"Trincomalee","precipitation":"1000 mm","temperature":"20 C","windspeed":"5.0 m/s"}]},"policyName":"abac","statusMessage":"OPA Allowed"} + +## PERMIT for policy:zone +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"zone", "policyFilter": ["has_zone_access"], "input":{"actions": ["view"],"log_id": "log1", "datatypes": ["access", "user"],"time_period": {"from": "2024-11-01T09:00:00Z","to": "2024-11-01T10:00:00Z"},"zone_id": "zoneA"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision +{"decision":"PERMIT","output":{"has_zone_access":[{"access":"granted","user":"user1"}]},"policyName":"zone","statusMessage":"OPA Allowed"} + +## DENY for policy: zone + +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"zone", "policyFilter": ["has_zone_access"], "input":{"actions": ["edit"],"log_id": "log1", "datatypes": ["access", "user"],"time_period": {"from": "2024-11-01T00:00:00Z","to": "2024-11-01T00:00:00Z"},"zone_id": "zoneA"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision +{"decision":"DENY","output":{"has_zone_access":[]},"policyName":"zone","statusMessage":"OPA Denied"} + +## PERMIT for policy:vehicle + +curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"vehicle", "policyFilter": ["user_has_vehicle_access"], "input":{"actions": ["use"],"user":"user1", "vehicle_id": "v1", "attributes": ["type", "status"]}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision + +{"decision":"PERMIT","output":{"user_has_vehicle_access":[{"status":"available","type":"car"}]},"policyName":"vehicle","statusMessage":"OPA Allowed"} + +## PERMIT for policy:docs + +`curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"docs", "policyFilter": ["has_access_to_file"], "input":{"action": "read","file_id": "file1","access_level": "admin","attributes": ["owner", "size"]}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision + +{"decision":"PERMIT","output":{"has_access_to_file":[{"owner":"user1","size":"10MB"}]},"policyName":"docs","statusMessage":"OPA Allowed"}` + +## DENY for policy:docs + +`curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"docs", "policyFilter": ["has_access_to_file"], "input":{"action": "view","file_id": "file1","access_level": "employee","attributes": ["owner", "size"]}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision + +{"decision":"DENY","output":{"has_access_to_file":[]},"policyName":"docs","statusMessage":"OPA Denied"}` + + ## HealthCheck API Call With Response curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -X GET http://0.0.0.0:8282/policy/pdpx/v1/healthcheck diff --git a/test/data/abac/data.json b/test/data/abac/data.json new file mode 100644 index 0000000..77b5668 --- /dev/null +++ b/test/data/abac/data.json @@ -0,0 +1,94 @@ +{ + "sensor_data": [ + { + "id": "0001", + "location": "Sri Lanka", + "temperature": "28 C", + "precipitation": "1000 mm", + "windspeed": "5.5 m/s", + "humidity": "40%", + "particle_density": "1.3 g/l", + "timestamp": "2024-02-26" + }, + { + "id": "0002", + "location": "Colombo", + "temperature": "30 C", + "precipitation": "1200 mm", + "windspeed": "6.0 m/s", + "humidity": "45%", + "particle_density": "1.5 g/l", + "timestamp": "2024-02-26" + }, + { + "id": "0003", + "location": "Kandy", + "temperature": "25 C", + "precipitation": "800 mm", + "windspeed": "4.5 m/s", + "humidity": "60%", + "particle_density": "1.1 g/l", + "timestamp": "2024-02-26" + }, + { + "id": "0004", + "location": "Galle", + "temperature": "35 C", + "precipitation": "500 mm", + "windspeed": "7.2 m/s", + "humidity": "30%", + "particle_density": "1.8 g/l", + "timestamp": "2024-02-27" + }, + { + "id": "0005", + "location": "Jaffna", + "temperature": "-5 C", + "precipitation": "300 mm", + "windspeed": "3.8 m/s", + "humidity": "20%", + "particle_density": "0.9 g/l", + "timestamp": "2024-02-27" + }, + { + "id": "0006", + "location": "Trincomalee", + "temperature": "20 C", + "precipitation": "1000 mm", + "windspeed": "5.0 m/s", + "humidity": "55%", + "particle_density": "1.2 g/l", + "timestamp": "2024-02-28" + }, + { + "id": "0007", + "location": "Nuwara Eliya", + "temperature": "25 C", + "precipitation": "600 mm", + "windspeed": "4.0 m/s", + "humidity": "50%", + "particle_density": "1.3 g/l", + "timestamp": "2024-02-28" + }, + { + "id": "0008", + "location": "Anuradhapura", + "temperature": "28 C", + "precipitation": "700 mm", + "windspeed": "5.8 m/s", + "humidity": "40%", + "particle_density": "1.4 g/l", + "timestamp": "2024-02-29" + }, + { + "id": "0009", + "location": "Matara", + "temperature": "32 C", + "precipitation": "900 mm", + "windspeed": "6.5 m/s", + "humidity": "65%", + "particle_density": "1.6 g/l", + "timestamp": "2024-02-29" + } + ] +} diff --git a/test/data/account/data.json b/test/data/account/data.json new file mode 100644 index 0000000..df263d3 --- /dev/null +++ b/test/data/account/data.json @@ -0,0 +1,16 @@ +{ + "account_attributes":{ + "11111":{ + "owner":"alice", + "amount":10000 + }, + "22222":{ + "owner":"bob", + "amount":10000 + }, + "33333":{ + "owner":"cam", + "amount":10000 + } + } +} diff --git a/test/data/action/data.json b/test/data/action/data.json new file mode 100644 index 0000000..99145b7 --- /dev/null +++ b/test/data/action/data.json @@ -0,0 +1,43 @@ +{ + "user_roles": { + "alice": [ + "admin" + ], + "bob": [ + "editor" + ], + "charlie": [ + "viewer" + ] + }, + "role_permissions": { + "admin": { + "actions": [ + "read", + "write", + "delete" + ], + "resources": [ + "server", + "database" + ] + }, + "editor": { + "actions": [ + "read", + "write" + ], + "resources": [ + "server" + ] + }, + "viewer": { + "actions": [ + "read" + ], + "resources": [ + "server" + ] + } + } +} diff --git a/test/data/organization/data.json b/test/data/organization/data.json new file mode 100644 index 0000000..35fe4a1 --- /dev/null +++ b/test/data/organization/data.json @@ -0,0 +1,32 @@ +{ + "acls": [ + { + "user": "alice", + "actions": [ + "edit", + "read" + ], + "component": "component_A", + "project": "project_A", + "organization": "org_A" + }, + { + "user": "bob", + "actions": ["read"], + "organization": "org_A" + }, + { + "user": "bob", + "action": ["edit"], + "component": "component_A", + "project": "project_B", + "organization": "org_A" + }, + { + "user": "charlie", + "action": ["read"], + "project": "project_B", + "organization": "org_A" + } + ] +} diff --git a/test/data/role/data.json b/test/data/role/data.json new file mode 100644 index 0000000..88ac41b --- /dev/null +++ b/test/data/role/data.json @@ -0,0 +1,63 @@ +{ + "user_roles": { + "alice": [ + "admin" + ], + "bob": [ + "employee", + "billing" + ], + "eve": [ + "customer" + ] + }, + "role_grants": { + "customer": [ + { + "action": "read", + "type": "dog" + }, + { + "action": "read", + "type": "cat" + }, + { + "action": "adopt", + "type": "dog" + }, + { + "action": "adopt", + "type": "cat" + } + ], + "employee": [ + { + "action": "read", + "type": "dog" + }, + { + "action": "read", + "type": "cat" + }, + { + "action": "update", + "type": "dog" + }, + { + "action": "update", + "type": "cat" + } + ], + "billing": [ + { + "action": "read", + "type": "finance" + }, + { + "action": "update", + "type": "finance" + } + ] + } +} + diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 6778882..273fd1d 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -99,7 +99,10 @@ services: - ./policy-new.yaml:/app/policy-new.yaml - type: bind source: ./policies - target: /app/policies + target: /opt/policies + - type: bind + source: ./data + target: /opt/data environment: LOG_LEVEL: debug @@ -108,6 +111,7 @@ services: GROUPID: opa-pdp API_USER: policyadmin API_PASSWORD: "zb!XztG34" + JAASLOGIN: org.apache.kafka.common.security.scram.ScramLoginModule required username="policy-opa-pdp-ku" password="pzmdwfFvBhv21mSD7dieHoUZf2aobdqR" entrypoint: sh wait_for_port.sh command: [ '-c', './policy-opa-pdp.sh', diff --git a/version b/version index 3eefcb9..90a27f9 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.0.0 +1.0.5 -- 2.16.6